2010-07-07 10 views
8

मैं सी सीखने की प्रक्रिया में हूं। मेरे पास एक विधि है जो 3 स्ट्रिंग लेती है और उन्हें कुछ ऑपरेशन करने के लिए जोड़ती है। जीसीसी कंपाइलर का उपयोग करके मेरा पहला कार्यान्वयन निम्नलिखित था।स्ट्रिंग मैनिपुलेशन और मेमोरी आवंटन - सी

void foo(const char *p1, const char *p2, const char *p3) 
{ 
    size_t length = strlen(p1) + strlen(p2) + strlen(p3); 
    char combined[length + 1]; 
    memset(combined, 0, length + 1); 
    strcat(combined, p1); 
    strcat(combined, p2); 
    strcat(combined, p3); 
    printf("Result : %s", combined); 
} 

int main() 
{ 
    foo("hello ", "world ", "how"); 
    return 0; 
} 

यह अच्छी तरह से काम करता है। लेकिन जब मैंने इसे cc -Wall -pedantic -g foo.c -o foo का उपयोग करके संकलित किया, तो मुझे ISO C90 forbids variable length array ‘combined’ जैसी चेतावनियां मिलनी शुरू हुईं। एमएसवीसी इस कोड को संकलित नहीं कर रहा था। बदल दिया तरह

void foo(const char *p1, const char *p2, const char *p3) 
{ 
    size_t length = strlen(p1) + strlen(p2) + strlen(p3); 
    char *combined = (char *) malloc(length + 1); 
    memset(combined, 0, length + 1); 
    strcat(combined, p1); 
    strcat(combined, p2); 
    strcat(combined, p3); 
    printf("Result : %s", combined); 
    free(combined); 
} 

प्रश्न

  1. कोड यह सही कार्यान्वयन है?
  2. यदि परिवर्तनीय लंबाई सरणी मानक का हिस्सा नहीं हैं, तो जीसीसी ने इसे क्यों लागू किया? यदि कोड केवल जीसीसी पर संकलित होने की उम्मीद है, तो परिवर्तनीय सरणी का उपयोग मॉलोक का उपयोग करने से बेहतर विकल्प होगा?
  3. मुझे लगता है कि अंगूठे नियम है, अगर स्मृति आवश्यक है संकलन समय पर जानता है, तो सरणी का उपयोग करें और आवश्यक स्मृति आवंटित करने के लिए malloc का उपयोग करें। क्या ये सही है?
  4. मेरा कोड जीसीसी और एमएसवीसी पर संकलित होने की उम्मीद है। मैं आमतौर पर जीसीसी पर विकास कर रहा हूं। तो संकलक झंडे क्या हैं जो अधिकतम पोर्टेबिलिटी सुनिश्चित करता है? वर्तमान में मैं -Wall -pedantic का उपयोग कर रहा हूं। क्या मुझे -ansi का भी उपयोग करना चाहिए? एमएसवीसी में उपलब्ध समकक्ष झंडे क्या होंगे?
  5. पोर्टेबल सी कोड लिखते समय विचार करने वाली अन्य आम बातों क्या हैं?
+0

http: // stackoverflow देखें।कॉम/प्रश्न/30 9 3049/अलग-व्यवहार-के-कंपाइलर्स-साथ-सरणी आवंटन – PeterK

+1

(1) हां यह है, जैसा कि आपने बिंदु 3 (2) में उल्लेख किया है क्योंकि जीसीसी आईएसओ सी 0 9 के अलावा अन्य मानकों का भी समर्थन करता है। (5) http://www.google.com/search?q=writing+portable+C+code वीएलए को गतिशील रूप से आवंटित करना हमेशा बेहतर होता है क्योंकि आप (एम/सी) आवंटन के वापसी मूल्य की जांच कर सकते हैं देखें कि आवंटन सफल था या नहीं – itisravi

+0

@itisravi - आपको टिप्पणी में जवाब देने के बजाय जवाब देना चाहिए। टिप्पणी लंबाई प्रतिबंधों के कारण, वीएलए बनाम गतिशील आवंटन पर आपकी सिफारिश थोड़ा सा स्पैस है। मैं इसके साथ सहमत हूं, और मुझे पता है कि आप क्या प्राप्त कर रहे हैं, लेकिन यह अस्पष्ट है क्योंकि टिप्पणियों के उत्तर बहुत कम हैं। यही कारण है कि हमारे पास जवाब हैं। ;) –

उत्तर

8

यह अच्छी तरह से काम करता है। लेकिन जब मैंने इसका उपयोग करके संकलित किया, सीसी -Wall -pedantic -g foo.c -o foo, मुझे आईएसओ सी 9 0 वर्ड्स वैरिएबल लम्बाई सरणी 'संयुक्त' जैसी चेतावनियां मिलनी शुरू हुईं।

-std=c99 विकल्प (gcc) के साथ संकलन करने का प्रयास करें।

एमएसवीसी इस कोड को संकलित नहीं कर रहा था।

जैसे कोड बदल गए हैं यदि परिवर्तनीय लंबाई सरणी मानक का हिस्सा नहीं हैं, तो जीसीसी ने इसे क्यों लागू किया?

वीएलए आईएसओ सी 99 (जीसीसी और जी ++ (एक विस्तार के रूप में) वीएलए का हिस्सा हैं) का हिस्सा हैं। एमएसवीसी अभी भी केवल सी 8 9 का समर्थन करता है।

मेरा कोड जीसीसी और एमएसवीसी पर संकलित होने की उम्मीद है।

तब आपको अपने कोड IMHO में वीएलए का उपयोग नहीं करना चाहिए।

3

परिवर्तनीय-लंबाई सरणी पहले आईएसओ सी मानक (जिसे "सी 8 9", "सी 0 9" या "एएनएसआई सी" के रूप में जाना जाता है) का हिस्सा नहीं था। हालांकि, वे नवीनतम आईएसओ सी मानक ("सी 99" के रूप में जाना जाता है) का एक हिस्सा हैं।

जीसीसी "सख्त C90", "C90-साथ-जीएनयू-C-एक्सटेंशन", और "C99" (हालांकि यह नहीं करता है पूरी तरह से C99 लागू, यह काफी करीब है सहित कई मोड, में अपने कोड संकलन कर सकते हैं अधिकांश व्यावहारिक उद्देश्यों के लिए)।

डिफ़ॉल्ट रूप से, जीसीसी "सी 90-साथ-जीएनयू-सी-एक्सटेंशन" का उपयोग करता है, यही कारण है कि आपका कोड शिकायत के बिना संकलित करता है। -pedantic का उपयोग करके प्रासंगिक मानक (इस मामले में, सी 9 0) द्वारा सभी आवश्यक चेतावनियों को उत्सर्जित करने के लिए कहा जाता है, और आपके कोड द्वारा ऐसी चेतावनी की आवश्यकता होती है। यदि आप जीसीसी को -std=c99 -pedantic झंडे देते हैं, तो इसे सी 99 बेस मानक के खिलाफ संकलित करने और सभी आवश्यक चेतावनियों को उत्सर्जित करने के लिए कहने के लिए, आपका कोड ठीक संकलित करता है। (: -std=c90 के लिए -ansi पर्याय है जब सी कोड संकलन या -ansi -pedantic)

आप यह सुनिश्चित करने के लिए अपने कोड बेस C90 मानक के साथ संगत है चाहते हैं, तो -std=c90 -pedantic का उपयोग करें। ध्यान दें कि एमएसवीसी सी 99 का समर्थन नहीं करता है।

7
  1. हाँ, यह है। वहां मानक के कोई विशिष्ट उल्लंघन नहीं है। memset समय की बर्बादी है, हालांकि यह किसी भी तरह से ओवरराइट होने जा रहा है (अपना पहला strcatstrcpy में बनाएं)। और आपको हमेशाmalloc को वापस लौटने के लिए जांचना चाहिए। कोई फर्क नहीं पड़ता कि क्या!
  2. सी 8 9/9 0 वर्तमान मानक नहीं है, सी 99 है। और सी 1 एक्स इतना दूर नहीं है। जीसीसी रक्तस्राव के किनारे के साथ रख रहा है।
  3. केवल स्थानीय सरणी का उपयोग करें यदि आपको फ़ंक्शन के अंत से परे जीवित रहने की आवश्यकता नहीं है। अन्यथा malloc आपकी सबसे अच्छी शर्त है, खासकर यदि आप संयुक्त स्ट्रिंग संयुक्त स्ट्रिंग करना चाहते हैं।
  4. मुझे लगता है कि जीसीसी में -std=c89 ध्वज या कुछ समान है। किसी भी मामले में, एमएसवीसी हमेशा मानक का पालन नहीं करता है :-)
  5. संकलित करें और इसे अक्सर दोनों प्लेटफार्मों पर परीक्षण करें। यह सुनिश्चित करने का एकमात्र तरीका है।

मैं के लिए चुनते हैं:

void foo (const char *p1, const char *p2, const char *p3) { 
    size_t length = strlen(p1) + strlen(p2) + strlen(p3); 
    char *combined = (char *) malloc(length + 1); 
    if (combined == NULL) { 
     printf("Result : <unknown since I could't get any memory>\n"); 
    } else { 
     strcpy(combined, p1); 
     strcat(combined, p2); 
     strcat(combined, p3); 
     printf("Result : %s", combined); 
     free(combined); 
    } 
} 

या, जब से तुम वास्तव में यह मुद्रण छोड़कर तार के साथ कुछ भी करने से नहीं कर रहे हैं:

void foo (const char *p1, const char *p2, const char *p3) { 
    printf("Result : %s%s%s", p1, p2, p3); 
} 

:-)

एक और मैंने जो रणनीति देखी है वह है "केवल आपको आवंटित करना है" रणनीति:

void foo (const char *p1, const char *p2, const char *p3) { 
    char str1k[1024]; 
    char *combined; 
    size_t length = strlen (p1) + strlen (p2) + strlen (p3) + 1; 
    if (length <= sizeof(str1k)) 
     combined = str1k; 
    else 
     combined = malloc (length); 
    if (combined == NULL) { 
     printf ("Result : <unknown since I couldn't get any memory>\n"); 
    } else { 
     strcpy (combined, p1); 
     strcat (combined, p2); 
     strcat (combined, p3); 
     printf ("Result : %s", combined); 
    } 
    if (combined != str1k) 
     free (combined); 
} 

जो स्ट्रिंग स्टोरेज का उपयोग करता है यदि संयुक्त स्ट्रिंग फिट होगी और केवल स्मृति को आवंटित नहीं करेगा। यदि स्ट्रिंग का बड़ा हिस्सा सीमा से कम में जोड़ता है तो इससे अक्सर पर्याप्त गति में सुधार हो सकता है।

+0

उत्कृष्ट जवाब। आपका बहुत बहुत धन्यवाद। मैं प्रिंटिंग के अलावा कुछ संचालन करने के लिए स्ट्रिंग का उपयोग करूँगा। उनको समझाने के लिए छोड़ दिया जाता है। –

0

इन मुद्दों के आसपास काम करने के लिए एक बहुत ही आम मुहावरे कॉलर को स्मृति का प्रबंधन करने देना है। तो स्मृति को आवंटित करने के बजाय (या तो स्टैक पर एक चर-लंबाई सरणी का उपयोग करके या malloc 'कुछ, या जो भी हो) द्वारा आप कॉलर को स्मृति प्रदान करने की अपेक्षा करते हैं। इस पर विचार करें:

int foo(const char *p1, const char *p2, const char *p3, char *buf, size_t bufsize) 
{ 
    size_t requiredSize = strlen(p1) + strlen(p2) + strlen(p3) + 1; 
    if (!buf) 
     return requiredSize; 
    if (requiredSize > bufsize) 
     return -1; 
    buf[0] = '\0'; 
    strcat(buf, p1); 
    strcat(buf, p2); 
    strcat(buf, p3); 
    return requiredSize; 
} 

int main() 
{ 
    /* simple case: caller knows that the buffer is large enough. */ 
    char buf[ 1024 ]; 
    foo("Hello", "World", "Bar", buf, sizeof(buf)); 
    printf("Result : %s\n", buf); 

    /* complicated case: caller wants to allocate buffer of just the right size */ 
    size_t bufsize = foo("Hello", "World", "Bar", NULL, 0); 
    char *buf2 = (char *)malloc(bufsize); 
    foo("Hello", "World", "Bar", buf2, bufsize); 
    free(buf2); 
} 

इस दृष्टिकोण का लाभ यह है कि foo रिसाव कभी नहीं होगा। इसके अलावा, कॉलर एक साधारण स्टैक-आधारित सरणी का उपयोग कर सकता है यदि यह उसके लिए काम करता है। यदि वह सटीक आकार जानना चाहता है तो वह foo पर कॉल कर सकता है और चौथे तर्क के रूप में NULL पास कर सकता है।