2013-10-05 7 views
10

जीसीसी के रूप में ही 4.8 मुझे एक त्रुटि दे है जब मैं निर्माणsnprintf त्रुटि। sizeof को तर्क गंतव्य

#include <string.h> 
#include <stdio.h> 

static inline void toto(char str[3]) 
{ 
    snprintf(str, sizeof(str), "XX"); 
} 

int main(){ 
    char str[3]; 
    toto(str); 
    return 0; 
} 

यहाँ जीसीसी त्रुटि

त्रुटि है: करने के लिए तर्क 'snprintf' कॉल में 'sizeof' है गंतव्य के रूप में एक ही अभिव्यक्ति; क्या आप एक स्पष्ट लंबाई प्रदान करना चाहते थे?

नोट: मैं -Wall -Werror झंडे का उपयोग कर रहा हूं जो चेतावनी को त्रुटि में परिवर्तित करता है।

There is something similar here एक टिप्पणी में, किसी ने इस

"निश्चित लंबाई बफ़र्स के लिए उत्तर दिया, मैं आमतौर पर strncpy (गंतव्य, src, sizeof (गंतव्य)) का उपयोग करें; गंतव्य [sizeof (गंतव्य) -1] = ' \ 0 '; यह पूर्ण समाप्ति की गारंटी देता है और स्निपिंटफ की तुलना में केवल कम परेशानी है कि बहुत से लोग स्नप्रिंटफ (dest, sizeof (dest), src) का उपयोग करते हैं, इसके बजाय और जब वे प्रोग्राम मनमाने ढंग से क्रैश होते हैं तो बहुत आश्चर्यचकित होते हैं। "

लेकिन यह गलत है: जीसीसी 4.8 कहना

"त्रुटि:? 'Strncpy' कॉल में 'sizeof' के लिए तर्क गंतव्य के रूप में एक ही अभिव्यक्ति है, आप एक स्पष्ट लंबाई प्रदान करने के लिए मतलब था [ -Werror = sizeof-सूचक-memaccess] "

in gcc 4.8 documentation, they are talking about this issue: वे कहते हैं:

-Wall के व्यवहार बदल गया है और अब नए चेतावनी झंडा शामिल -Wsizeof-p ointer-memaccess। इसके परिणामस्वरूप कोड में नई चेतावनियां हो सकती हैं जो जीसीसी के पिछले संस्करणों के साथ स्पष्ट रूप से संकलित होती हैं।

उदाहरण के लिए,

include string.h 

struct A { }; 

int main(void) 
{ 
    A obj; 
    A* p1 = &obj; 
    A p2[10]; 

    memset(p1, 0, sizeof(p1)); // error 
    memset(p1, 0, sizeof(*p1)); // ok, dereferenced 
    memset(p2, 0, sizeof(p2)); // ok, array 
    return 0; 
} 

देता है निम्न नैदानिक: चेतावनी: 'sizeof' करने के लिए तर्क 'शून्य memset (शून्य *, पूर्णांक, size_t)' कॉल के रूप में ही अभिव्यक्ति है गंतव्य; क्या आप इसे कम करने का मतलब था? [-Wsizeof-सूचक-memaccess] स्मृति (पी 1, 0, आकार (पी 1)); // त्रुटि ^ हालांकि इन चेतावनियों का संकलन विफलता में नतीजा नहीं होगा, अक्सर -वॉल के साथ संयोजन के रूप में उपयोग किया जाता है और नतीजतन, नई चेतावनियां नई त्रुटियों में बदल जाती हैं। ठीक करने के लिए, या तो अपमानजनक मेमसेट कॉल में अंतिम तर्क को याद करने के लिए फिर से लिखना। *

ठीक है, उनके उदाहरण में, यह स्पष्ट है कि कोड गलत था, लेकिन मेरे मामले में, snprintf/strncpy के साथ, मैं नहीं देखता क्यों, और मुझे लगता है कि यह जीसीसी की झूठी सकारात्मक त्रुटि है। सही ? आपकी मदद के लिए

धन्यवाद

+0

विषम, '-Wsizeof-pointer-memaccess' के लिए प्रलेखन मुझे लगता है कि अगर आप अपने पहले उदाहरण में 'char * str' लिखा था, तो यह चेतावनी देगा, लेकिन यह' char str [3 'के लिए चेतावनी नहीं देनी चाहिए ] '। G12+ के साथ – hobbs

+0

, मुझे कोई त्रुटि नहीं मिली। – PersianGulf

+0

जीसीसी 4.8.1 के साथ, मैं चेतावनी पुन: पेश नहीं कर सका। निश्चित रूप से आप 'char str [3]' और 'char * str' का उपयोग नहीं कर रहे हैं? –

उत्तर

8

एक सरणी पहला तत्व के लिए सूचक में decays जब आप एक समारोह के लिए पारित कर दिया। तो क्या आप

static inline void toto(char str[3]) {..}

में है एक सरणी लेकिन एक सूचक नहीं है।

इसलिए, जीसीसी सही चेतावनी देता है।

आप समारोह पैरामीटर में आकार निर्दिष्ट चाहे या के रूप में नहीं कोई फर्क नहीं पड़ता:

static inline void toto(char str[3]) 

और

static inline void toto(char str[]) 

और

static inline void toto(char *str) 

सब बराबर हैं।

इस पर यहाँ पढ़ें: what is array decaying?

4

test.c:

#include <stdio.h> 

void bar(char foo[1000]) 
{ 
    printf ("sizeof foo = %d\n", (int)(sizeof foo)); 
} 

int main() 
{ 
    char foo[1000]; 
    bar(foo); 
} 

चल:

bash $ ./test 
4 
bash $ 

इसलिए।

1
static inline void toto(char str[3]) 

एक समारोह है कि किसी भी आकार के सरणी ले जा सकते हैं परिभाषित करता है। 3 को अनदेखा किया गया है, और str को पॉइंटर के रूप में माना जाता है (printf("%d\n", sizeof(str)) को आजमाएं: मेरी मशीन पर, यह 64-बिट पॉइंटर के आकार के लिए 8 प्रिंट करता है)। संकलक वास्तव में इस मामले में सही है।

बजना एक उपयोगी चेतावनी यहाँ देता है:

test.c:6:25: warning: sizeof on array function parameter will return size of 
     'char *' instead of 'char [3]' [-Wsizeof-array-argument] 
    snprintf(str, sizeof(str), "XX"); 
2

अपने कार्य परिभाषा में, पैरामीटर घोषणा:

static inline void toto(char str[3]) 

एक सरणी के रूप में str घोषणा नहीं करता है (सी सरणी प्रकार के मापदंडों नहीं है)।

static inline void toto(char *str) 

3 चुपचाप नजरअंदाज कर दिया है: दरअसल, यह वास्तव में बराबर करने के लिए है।

तो sizeof(str) स्ट्रिंग धारकों के पात्रों की संख्या के साथ कुछ लेना देना नहीं है, यह केवल char* सूचक का आकार है।

यह एक नियम से परिणाम देता है जो कहता है कि एक सरणी प्रकार के साथ घोषित पैरामीटर पॉइंटर प्रकार के लिए "समायोजित" है। यह नियम से अलग है जो कहता है कि अधिकांश संदर्भों में सरणी प्रकार के अभिव्यक्ति को निश्चित रूप से परिवर्तित (या "क्षय") पॉइंटर्स में परिवर्तित किया जाता है। दो नियम एक साथ काम करने के लिए एक साथ काम करते हैं जो सरणी से संबंधित है, ऐसा लगता है कि यह सीधे सरणी से निपट रहा है, जब यह वास्तव में सरणी के तत्वों के पॉइंटर्स के साथ काम कर रहा है।

सी एरे और पॉइंटर्स के बीच संबंध अक्सर भ्रमित होता है। मैं comp.lang.c FAQ की धारा 6 पढ़ने की अनुशंसा करता हूं; यह समझाने का एक बहुत अच्छा काम करता है।

+0

सुनिश्चित नहीं है कि कोई भी इसे क्यों कम करेगा ... +1। –

संबंधित मुद्दे