2008-09-09 11 views
118

, ऑपरेटर सी में क्या करता है?अल्पविराम ऑपरेटर क्या करता है?

+0

संभावित डुप्लिकेट [अल्पविराम ऑपरेटर का उचित उपयोग क्या है?] (Http: // stackoverflow।कॉम/प्रश्न/179029 9 2/क्या-उचित-उपयोग-के-कॉमा-ऑपरेटर) –

+1

जैसा कि मैंने अपने उत्तर में नोट किया है, बाएं ऑपरेंड के मूल्यांकन के बाद एक अनुक्रम बिंदु है। यह एक फ़ंक्शन कॉल में अल्पविराम के विपरीत है जो केवल व्याकरणिक है। –

उत्तर

97

अभिव्यक्ति:

(expression1, expression2) 

पहले expression1 मूल्यांकन किया जाता है, तो expression2 मूल्यांकन किया जाता है, और expression2 का मूल्य पूरे अभिव्यक्ति के लिए दिया जाता है।

+1

तो अगर मैं लिखूं = = (5,4,3,2,1,0) तो आदर्श रूप से इसे 0 वापस करना चाहिए, सही? लेकिन मुझे 5 का मूल्य सौंपा जा रहा है? क्या आप कृपया मुझे यह समझने में मदद कर सकते हैं कि मैं गलत कहां जा रहा हूं? – Jayesh

+12

@ जेम्स: अल्पविराम ऑपरेशन का मूल्य हमेशा अंतिम अभिव्यक्ति का मूल्य होगा। किसी भी समय 'मेरे पास मूल्य 5, 4, 3, 2 या 1 नहीं होंगे। यह केवल 0 है। यह व्यावहारिक रूप से बेकार है जब तक कि अभिव्यक्तियों के साइड इफेक्ट न हों। –

+4

ध्यान दें कि अल्पविराम अभिव्यक्ति के एलएचएस के मूल्यांकन और आरएचएस के मूल्यांकन के बीच एक पूर्ण अनुक्रम बिंदु है (देखें [शाफिक यागहोर] (http://stackoverflow.com/users/1708801/shafik-yaghmour) [उत्तर] (http://stackoverflow.com/a/18444099/15168) सी 99 मानक से उद्धरण के लिए)। यह अल्पविराम ऑपरेटर की एक महत्वपूर्ण संपत्ति है। –

8

यह कई बयानों के मूल्यांकन का कारण बनता है, लेकिन परिणामी मूल्य (रावल्यू, मुझे लगता है) के रूप में केवल अंतिम का उपयोग करता है।

तो ...

int f() { return 7; } 
int g() { return 8; } 

int x = (printf("assigning x"), f(), g()); 

एक्स में परिणाम चाहिए 8.

3

करने के लिए सेट किया जा रहा पहले जवाब ने कहा है कि यह सब बयान का मूल्यांकन करता है, लेकिन अभिव्यक्ति के मूल्य के रूप में पिछले एक का उपयोग करता है के रूप में। व्यक्तिगत तौर पर मैं केवल पाश भाव में इसे उपयोगी पाया गया है:

for (tmp=0, i = MAX; i > 0; i--) 
2

केवल जगह मैं इसे उपयोगी किया जा रहा है देखा है जब आप (एक फैशनेबल पाश जहां भाव में से एक में एक से अधिक काम करने के लिए चाहते हैं लिखने शायद init अभिव्यक्ति या पाश अभिव्यक्ति की तरह कुछ:।

bool arraysAreMirrored(int a1[], int a2[], size_t size) 
{ 
    size_t i1, i2; 
    for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--) 
    { 
    if(a1[i1] != a2[i2]) 
    { 
     return false; 
    } 
    } 

    return true; 
} 

क्षमा मुझे अगर कोई वाक्यविन्यास त्रुटियों या अगर मैं कुछ भी मिश्रित सख्त सी मैं उनका तर्क है नहीं कर रहा हूँ कि, ऑपरेटर अच्छा तरीका है नहीं है कि है, लेकिन कर रहे हैं यही वह है जिसका आप इसका उपयोग कर सकते हैं। उपर्युक्त मामले में मैं शायद while लूप का उपयोग करूँगा ताकि इनिट और लूप पर एकाधिक अभिव्यक्तियां बी होंगी ई अधिक स्पष्ट है। (और मैं बजाय घोषित करने और फिर आरंभ करने के i1 और i2 इनलाइन प्रारंभ होगी .... ऐसा ऐसा।)

+0

मुझे लगता है कि आपका मतलब है i1 = 0, i2 = size -1 – frankster

+0

दरअसल! विधिवत सही – Owen

85

मैं while छोरों में सबसे अधिक इस्तेमाल किया देखा है:

string s; 
while(read_string(s), s.len() > 5) 
{ 
    //do something 
} 

यह करना होगा ऑपरेशन, फिर एक दुष्प्रभाव के आधार पर एक परीक्षण करें। अन्य तरीके से इस तरह यह करने के लिए होगा:

string s; 
read_string(s); 
while(s.len() > 5) 
{ 
    //do something 
    read_string(s); 
} 
+12

अरे, यह निफ्टी है! मुझे उस समस्या को ठीक करने के लिए अक्सर लूप में अपरंपरागत चीजें करना पड़ता था। – staticsan

+4

यद्यपि यह संभवतः कम अस्पष्ट और अधिक पठनीय होगा यदि आपने ऐसा कुछ किया: 'while (read_string (s) && s.len()> 5) '। जाहिर है कि अगर 'read_string' का रिटर्न वैल्यू नहीं है (या कोई सार्थक नहीं है) तो काम नहीं करेगा। (संपादित करें: क्षमा करें, यह ध्यान नहीं दिया कि यह पोस्ट कितना पुराना था।) – jamesdlin

+8

@staticsan '' (1) '' ब्रेक 'के साथ' शरीर में बयान 'का उपयोग करने से डरो मत। कोड के ब्रेक-आउट भाग को टेस्ट-डाउन टेस्ट में टेस्ट या डाउन में मजबूर करने की कोशिश करते हुए, अक्सर ऊर्जा की बर्बादी होती है और कोड को समझने में कठिनाई होती है। – potrzebie

26

अल्पविराम ऑपरेटर, एक में दो भाव या तो यह की ओर जोड़ती है उन दोनों को बाएँ से सही क्रम में मूल्यांकन। दायीं तरफ का मूल्य पूरी अभिव्यक्ति के मूल्य के रूप में वापस कर दिया जाता है। (expr1, expr2){ expr1; expr2; } जैसा है लेकिन आप फ़ंक्शन कॉल या असाइनमेंट में expr2 के परिणाम का उपयोग कर सकते हैं।

यह अक्सर for छोरों में देखा जाता है इस तरह आरंभ या एकाधिक चर बनाए रखने के लिए:

for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh) 
{ 
    /* do something with low and high and put new values 
     in newlow and newhigh */ 
} 
इस से

अलावा, मैं केवल यह "क्रोध में" एक अन्य मामले में इस्तेमाल किया गया है, जब दो ऊपर लपेटकर संचालन जो हमेशा एक मैक्रो में एक साथ जाना चाहिए।हम कोड है कि एक नेटवर्क पर भेजने के लिए एक बाइट बफर में विभिन्न द्विआधारी मूल्यों की नकल की थी, और एक सूचक को बनाए रखा है, जहां हम अप करने के लिए मिला था:

unsigned char outbuff[BUFFSIZE]; 
unsigned char *ptr = outbuff; 

*ptr++ = first_byte_value; 
*ptr++ = second_byte_value; 

send_buff(outbuff, (int)(ptr - outbuff)); 

कहाँ मूल्यों short या int रों हम ऐसा किया थे:

*((short *)ptr)++ = short_value; 
*((int *)ptr)++ = int_value; 

बाद में हम पढ़ते हैं कि यह वास्तव में वैध सी नहीं था, क्योंकि (short *)ptr अब एक एल-मूल्य है और वृद्धि की जाती नहीं किया जा सकता है, हालांकि समय हमारे संकलक मन नहीं था। इसे ठीक करने के लिए, हम दो में अभिव्यक्ति विभाजित:

*(short *)ptr = short_value; 
ptr += sizeof(short); 

हालांकि, इस पद्धति हर समय में दोनों कथनों डाल करने के लिए याद सभी डेवलपर्स पर भरोसा किया। हम एक समारोह चाहते थे जहां आप आउटपुट पॉइंटर, मान और मूल्य के प्रकार में पास हो सकें। यह किया जा रहा है सी, सी ++ नहीं टेम्पलेट्स के साथ, हम एक समारोह एक मनमाना प्रकार ले नहीं कर सकता है, इसलिए हम किसी मैक्रो पर बसे:

#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type)) 

अल्पविराम ऑपरेटर हम भाव में या के रूप में उपयोग करने में सक्षम थे का उपयोग करके बयान के रूप में हम चाहते थे:

if (need_to_output_short) 
    ASSIGN_INCR(ptr, short_value, short); 

latest_pos = ASSIGN_INCR(ptr, int_value, int); 

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff)); 

मैं सुझाव नहीं दे रहा हूं कि इनमें से कोई भी उदाहरण अच्छी शैली है! दरअसल, मुझे लगता है कि स्टीव मैककनेल के कोड पूर्णfor लूप में अल्पविराम ऑपरेटरों का उपयोग करने के खिलाफ सलाह देने के लिए सलाह देते हैं: पठनीयता और रखरखाव के लिए, लूप को केवल एक चर द्वारा नियंत्रित किया जाना चाहिए, और for लाइन में अभिव्यक्तियों में केवल लूप होना चाहिए -control कोड, प्रारंभिकरण या लूप रखरखाव के अन्य अतिरिक्त बिट्स नहीं।

+0

धन्यवाद! यह स्टैक ओवरफ्लो पर मेरा पहला जवाब था: तब से मैंने शायद सीखा है कि समानता का मूल्य निर्धारण किया जाना चाहिए :-)। –

+0

कभी-कभी मैं थोड़ा सा वर्बोजिटी मानता हूं जैसा कि यहां एक मामला है जहां आप समाधान के विकास का वर्णन करते हैं (आप वहां कैसे पहुंचे)। –

20

comma operator बाएं ऑपरेंड का मूल्यांकन करेगा, परिणाम छोड़ देगा और फिर सही ऑपरेंड का मूल्यांकन करेगा और यह परिणाम होगा। मुहावरेदार उपयोग लिंक में बताया गया है जब एक for पाश में प्रयोग किया जाता चर आरंभ है, और यह निम्न उदाहरण देता है:

void rev(char *s, size_t len) 
{ 
    char *first; 
    for (first = s, s += len - 1; s >= first; --s) 
     /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
     putchar(*s); 
} 

अन्यथा वहाँ नहीं कई महानअल्पविराम ऑपरेटर का प्रयोग हैं , हालांकि यह easy to abuse है जो कोड को उत्पन्न करने के लिए है जो पढ़ने और बनाए रखने में मुश्किल है।

expression: 
    assignment-expression 
    expression , assignment-expression 

और पैरा 2 का कहना है::

draft C99 standard से इस प्रकार व्याकरण है

एक अल्पविराम ऑपरेटर की बाईं संकार्य एक शून्य अभिव्यक्ति के रूप में मूल्यांकन किया जाता है; इसके मूल्यांकन के बाद एक अनुक्रम बिंदु है। फिर सही ऑपरेंड का मूल्यांकन किया जाता है; परिणाम का प्रकार और मूल्य है।9 7) यदि किसी अल्पविराम ऑपरेटर के परिणाम को संशोधित करने या अगले अनुक्रम बिंदु के बाद इसे एक्सेस करने का प्रयास किया जाता है, तो व्यवहार अपरिभाषित होता है।

फ़ुटनोट 97 का कहना है:

अल्पविराम ऑपरेटर एक lvalue उपज नहीं है।

जो आप अल्पविराम ऑपरेटर के परिणाम के आवंटित नहीं कर सकते हैं।

1 4 
:

#include <stdio.h> 

int main() 
{ 
    int x, y ; 

    x = 1, 2 ; 
    y = (3,4) ; 

    printf("%d %d\n", x, y) ; 
} 

निम्नलिखित उत्पादन होगा:

यह अल्पविराम ऑपरेटर lowest precedence है और इसलिए वहाँ मामलों में जहां () का उपयोग कर एक बड़ा फर्क कर सकते हैं उदाहरण के लिए, कर रहे हैं कि नोट करना महत्वपूर्ण है

4

अल्पविराम ऑपरेटर कुछ सार्थक नहीं करता है, यह 100% अनिवार्य विशेषता है। इसका मुख्य उपयोग "लोग स्मार्ट होने की कोशिश कर रहे हैं" और इसलिए इसे (अनजाने में) obfuscate पठनीय कोड का उपयोग करें। उपयोग के मुख्य क्षेत्र, छोरों के लिए अंधेरा करना उदाहरण के लिए है:

for(int i=0, count=0; i<x; i++, count++) 

कहाँ int i=0, count=0 वास्तव में अल्पविराम ऑपरेटर नहीं है, लेकिन एक घोषणा सूची (हम पहले से ही यहाँ भ्रमित कर रहे हैं) है। i++, count++ अल्पविराम ऑपरेटर है, जो बाएं ऑपरेंड का मूल्यांकन करता है और फिर सही ऑपरेंड का मूल्यांकन करता है। अल्पविराम ऑपरेटर का नतीजा सही संचालन का परिणाम है। बाएं ऑपरेंड का परिणाम त्याग दिया गया है।

लेकिन इसके बाद के संस्करण कोड अल्पविराम ऑपरेटर के बिना एक और अधिक पठनीय तरह से लिखा जा सकता है: अनुक्रम बिंदुओं के बारे में विचार-विमर्श कृत्रिम

int count = 0; 
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere 
{ 
    ... 
    count++; 
} 

अल्पविराम ऑपरेटर मैंने देखा है की केवल वास्तविक उपयोग करते हैं, है , क्योंकि कॉमा ऑपरेटर बाएं और दाएं ऑपरेटरों के मूल्यांकन के बीच एक अनुक्रम बिंदु के साथ आता है।

तो अगर आप इस तरह की कुछ अपरिभाषित व्यवहार कोड है:

printf("%d %d", i++, i++); 

आप वास्तव में यह

printf("%d %d", (0,i++), (0,i++)); 

लिख कर चालू कर सकते हैं केवल अनिर्दिष्ट व्यवहार (फ़ंक्शन पैरामीटर के मूल्यांकन के आदेश) में नहीं है अब i++ के प्रत्येक मूल्यांकन के बीच एक अनुक्रम बिंदु, इसलिए कम से कम कार्यक्रम को क्रैश करने और अब जला देने का जोखिम नहीं होगा, भले ही फ़ंक्शन पैरामीटर के मूल्यांकन का क्रम निर्दिष्ट न हो।

बेशक कोई भी असली एप्लिकेशन में ऐसा कोड नहीं लिखता है, यह सी भाषा में अनुक्रम बिंदुओं के बारे में भाषा-वकील चर्चाओं के लिए उपयोगी है।

अल्पविराम ऑपरेटर को मिसरा-सी: 2004 और मिसा-सी: 2012 द्वारा प्रतिबंधित किया गया है, जिसमें तर्क कम है कि यह कम पठनीय कोड बनाता है।

+7

आपका "अनिर्दिष्ट" संस्करण अभी भी अनिर्धारित है। तर्कों का मूल्यांकन ओवरलैप हो सकता है, ताकि पहले दो 0 का मूल्यांकन किया जा सके, फिर एक अनुक्रम बिंदु है, और अंततः दो वृद्धि का मूल्यांकन किया जाता है। यह आवश्यकता को पूरा करता है कि अल्पविराम एलएचएस और आरएचएस के बीच एक अनुक्रम बिंदु है। आपके लूप के लिए 'लूप' के लिए, 'जारी रखें' पर विचार करें। आप जो सुझाव देते हैं वह वास्तव में समतुल्य नहीं है। पठनीयता के लिए, 'srC++, dst ++' पर विचार करें, जहां कोड में दोनों वृद्धि एक साथ रखते हुए पाठक को यह सत्यापित करना आसान हो जाता है कि दोनों पॉइंटर्स बिल्कुल वही बढ़ते हैं। – hvd

+1

@hvd मुझे विश्वास नहीं है कि सख्ती से अनुरूप कार्यान्वयन अनुक्रम बिंदुओं को हटाने की अनुमति है, जो आपकी टिप्पणी से पता चलता है। कोई भी क्यों जारी रहेगा? यह केवल स्पेगेटी कोडिंग (और एमआईएसआरए द्वारा प्रतिबंधित) के लिए भी उपयोगी है। और लूप _is_ किसी भी तरह के परिणामस्वरूप, परिणाम के संदर्भ में और सी की "सार मशीन" के संदर्भ में। और मुझे सच में नहीं लगता कि 'srC++, dst ++; '' srC++ से अधिक पठनीय है; (न्यूलाइन) डीएसटी ++; '। मुझे बहुत कम संदेह है। – Lundin

+4

ठीक है, फिर 0 का मूल्यांकन करें, 0 का मूल्यांकन करें, अनुक्रम बिंदु, अनुक्रम बिंदु, i ++ का मूल्यांकन करें, i ++ का मूल्यांकन करें। वही परिणाम, इसलिए मुझे नहीं लगता कि भेद महत्वपूर्ण है। जैसा कि srC++, dst ++ के लिए, मैं उस समय का जिक्र कर रहा था जब यह किसी के लिए प्रकट होता है, क्योंकि आपका उत्तर उस पर केंद्रित है। – hvd

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