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


167

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



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

2
@SergeyK। - यह देखते हुए कि यह एक दूसरे से वर्षों पहले पूछा गया था और उत्तर दिया गया था, यह अधिक संभावना है कि दूसरा इस प्रश्न का दोहराव है। हालांकि, दूसरा भी सी और सी ++ दोनों के साथ दोहरे-टैग वाला है , जो एक उपद्रव है। यह एक सी-ओनली Q & A है, जिसमें अच्छे उत्तर हैं।
जोनाथन लेफ़लर

जवाबों:


129

भाव:

(expression1,  expression2)

पहले एक्सप्रेशन 1 का मूल्यांकन किया जाता है, फिर एक्सप्रेशन 2 का मूल्यांकन किया जाता है, और एक्सप्रेशन 2 का मान पूरे एक्सप्रेशन के लिए वापस कर दिया जाता है।


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

19
@ नाम: अल्पविराम ऑपरेशन का मूल्य हमेशा अंतिम अभिव्यक्ति का मूल्य होगा। किसी भी बिंदु iपर 5, 4, 3, 2 या 1. मान नहीं होंगे । यह बस 0. है। यह व्यावहारिक रूप से बेकार है जब तक कि भावों पर दुष्प्रभाव न हो।
जेफ मर्काडो

6
ध्यान दें कि अल्पविराम अभिव्यक्ति के LHS के मूल्यांकन और RHS के मूल्यांकन के बीच पूर्ण अनुक्रम बिंदु है (देखें C99 मानक से एक उद्धरण के लिए Shafik Yaghmour का जवाब )। यह अल्पविराम ऑपरेटर की एक महत्वपूर्ण संपत्ति है।
जोनाथन लेफ्लर

5
i = b, c;के बराबर है, (i = b), cक्योंकि असाइनमेंट =में अल्पविराम ऑपरेटर की तुलना में अधिक पूर्वता है ,। अल्पविराम ऑपरेटर की सबसे कम पूर्वता है।
साइकिल चालक

1
मुझे चिंता है कि कोष्ठक दो मामलों में भ्रामक हैं: (1) वे आवश्यक नहीं हैं - अल्पविराम संचालक को कोष्ठकों से घिरा नहीं होना चाहिए; और (2) वे एक फ़ंक्शन कॉल की तर्क सूची के आसपास कोष्ठक के साथ भ्रमित हो सकते हैं - लेकिन तर्क सूची में अल्पविराम अल्पविराम ऑपरेटर नहीं है। हालांकि, इसे ठीक करना पूरी तरह से मामूली नहीं है। हो सकता है: बयान में: expression1, expression2;पहले expression1मूल्यांकन किया जाता है, संभवतः इसके साइड-इफेक्ट्स के लिए (जैसे कि एक फ़ंक्शन को कॉल करना), फिर एक अनुक्रम बिंदु है, फिर expression2मूल्यांकन किया जाता है और मान लौटाया जाता है ...
जोनाथन लेफ़लर

119

मैंने 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);
}

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

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

11
@staticsan शरीर में while (1)एक break;बयान के साथ उपयोग करने से डरो मत । कोड के ब्रेक-आउट भाग को परीक्षण में या डाउन-टू-टेस्ट में लागू करने की कोशिश करना, अक्सर ऊर्जा की बर्बादी है और कोड को समझने में कठिन बनाता है।
पोट्रजेबी

8
@jamesdlin ... और लोग अभी भी इसे पढ़ते हैं। यदि आपके पास कहने के लिए कुछ उपयोगी है, तो कहें। फ़ोरम में पुनर्जीवित धागे के साथ समस्याएं हैं क्योंकि थ्रेड आमतौर पर अंतिम पोस्ट की तारीख से हल होते हैं। StackOverflow में ऐसी समस्याएँ नहीं हैं।
दिमितर स्लावचेव

3
@potrzebie मुझे कॉमा दृष्टिकोण बहुत पसंद है while(1)और से बेहतर है break;
माइकल

38

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

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

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

से मसौदा C99 मानक व्याकरण इस प्रकार है:

expression:
  assignment-expression
  expression , assignment-expression

और पैराग्राफ 2 कहता है:

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

फुटनोट 97 कहते हैं:

अल्पविराम ऑपरेटर लैवल्यू नहीं करता है ।

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

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

#include <stdio.h>

int main()
{
    int x, y ;

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

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

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

1 4

28

अल्पविराम ऑपरेटर दोनों पक्षों को एक में जोड़ता है, दोनों का मूल्यांकन बाएं से दाएं क्रम में करता है। दाहिने हाथ की ओर का मूल्य पूरे अभिव्यक्ति के मूल्य के रूप में वापस किया जाता है। (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);

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

#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लाइन में अभिव्यक्तियों में केवल लूप-कंट्रोल कोड होना चाहिए, आरंभीकरण या लूप रखरखाव के अन्य अतिरिक्त बिट्स नहीं।


धन्यवाद! यह StackOverflow पर मेरा पहला जवाब था: तब से मैंने शायद यह जान लिया है कि संक्षिप्तता को महत्व दिया जाना है :-)।
पॉल स्टीफेंसन

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

8

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

इसलिए...

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

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

x में परिणाम के लिए 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लूप का उपयोग करूंगा बजाय इसके कि init और loop पर कई एक्सप्रेशन अधिक स्पष्ट होंगे। (और मैं घोषित करने के बजाय i1 और i2 इनलाइन को इनिशियलाइज़ करूँगा और फिर इनिशियलाइज़िंग करूँगा .... ब्ला ब्ला ब्ला)।


मुझे लगता है कि आप का मतलब i1 = 0, i2 = आकार -1
फ्रैंकस्टर

-2

मैं इसे केवल @Rajesh और @JeffMercado से प्रश्नों को संबोधित करने के लिए पुनर्जीवित कर रहा हूं जो मुझे लगता है कि बहुत महत्वपूर्ण हैं क्योंकि यह शीर्ष खोज इंजन हिट में से एक है।

उदाहरण के लिए कोड का निम्नलिखित स्निपेट लें

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

यह छपेगा

1 5

iअधिकांश जवाबों के द्वारा इस मामले को समझा जाता है। सभी अभिव्यक्तियों का मूल्यांकन बाएं से दाएं क्रम में किया जाता है लेकिन केवल अंतिम को ही सौंपा जाता है i। का परिणाम है( अभिव्यक्ति ) is1`।

jमामला अलग पूर्वता नियमों का पालन करती बाद से ,सबसे कम ऑपरेटर पूर्वता है। उन नियमों के कारण, संकलक असाइनमेंट-एक्सप्रेशन, स्थिर, स्थिर ... देखता है । अभिव्यक्तियों का फिर से बाएं-से-दाएं क्रम में मूल्यांकन किया जाता है और उनके दुष्प्रभाव दिखाई देते हैं, इसलिए,j इसके 5परिणामस्वरूप हैj = 5

अंतरराज्यीय रूप से, int j = 5,4,3,2,1;भाषा की अनुमति नहीं है। एक आरंभिक एक असाइनमेंट-अभिव्यक्ति की उम्मीद करता है, इसलिए एक प्रत्यक्ष ,ऑपरेटर की अनुमति नहीं है।

उम्मीद है की यह मदद करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.