साइज़ोफ़ (x ++) क्यों नहीं बढ़ाता x?


505

यहाँ देव c ++ विंडोज़ में संकलित कोड है:

#include <stdio.h>

int main() {
    int x = 5;
    printf("%d and ", sizeof(x++)); // note 1
    printf("%d\n", x); // note 2
    return 0;
}

मुझे नोट 1x को निष्पादित करने के बाद 6 होने की उम्मीद है । हालाँकि, आउटपुट है:

4 and 5

क्या कोई समझा सकता है कि नोट 1 केx बाद वेतन वृद्धि क्यों नहीं होती है ?


37
मैं ध्यान देता हूं कि DevC ++ एक बहुत पुराना पुराना संकलक का उपयोग करता है, आप एक नए IDE में अपग्रेड करना चाहते हैं, उदाहरण के लिए कोडब्लॉक एक्लिप्स या विजुअल स्टूडियो
टॉम जे नोवेल

4
++ x x ++, cygwin और gcc 3.4.4 के समान परिणाम देता है।
११:११

6
@Tim Pletzcker क्योंकि पहला मान चर का आकार है, और चर ही नहीं है।
सर्फबटलर

मेरे जवाब को इस विलय के साथ जोड़ा गया था क्योंकि मेरा जवाब वास्तव में दिखाता है कि आप उस मामले में रन-टाइम मूल्यांकन कैसे प्राप्त कर सकते हैं VLAsजिसमें कोई भी अन्य नहीं करता है।
शफीक याघमोर

2
इस तरह के लेखन से बचना चाहिए क्योंकि इससे अवांछनीय दुष्प्रभाव हो सकते हैं। आपका प्रश्न पहले से ही उनमें से एक है।
15:66 बजे user666412

जवाबों:


537

से C99 स्टैंडर्ड (जोर मेरा है)

6.5.3.4/2

आकारऑफ़ ऑपरेटर अपने ऑपरेंड के आकार (बाइट्स में) का उत्पादन करता है, जो एक प्रकार का एक अभिव्यक्ति या कोष्ठक नाम हो सकता है। आकार ऑपरेंड के प्रकार से निर्धारित होता है। परिणाम एक पूर्णांक है। यदि ऑपरेंड का प्रकार एक चर लंबाई सरणी प्रकार है, तो ऑपरेंड का मूल्यांकन किया जाता है; अन्यथा, ऑपरेंड का मूल्यांकन नहीं किया जाता है और परिणाम पूर्णांक स्थिर होता है।


51
"यदि ऑपरेंड का प्रकार एक चर लंबाई सरणी प्रकार है, तो ऑपरेंड का मूल्यांकन किया जाता है" वाह! मैंने कभी महसूस नहीं किया कि
कोस

6
चर लंबाई सरणी प्रकार से आपका क्या मतलब है? इसका मतलब है कि ऑपरेंड एक सरणी है? इस मामले में कोड एक सरणी नहीं है। क्या आप मेरे लिए चीजें साफ कर सकते हैं?
नेगील आर। नोवल

37
एक चर लंबाई सरणी एक सरणी है जिसका आकार संकलन के दौरान एक अज्ञात मूल्य है, उदाहरण के लिए यदि आप Nस्टड से पढ़ते हैं और बनाते हैं int array[N]। यह C99 सुविधाओं में से एक है, जो C ++ में अनुपलब्ध है।
कोस

21
@LegendofCage, विशेष रूप से इसका मतलब यह होगा कि कुछ sizeof(int[++x])( जैसे , वास्तव में एक बुरा विचार, किसी भी तरह) का ++मूल्यांकन किया जा सकता है।
जेन्स गुस्तेद

3
@Joe Wreschnig: यह द्वारा मूल्यांकन किया जाता है gcc, clangऔर कम से ideone.com/Pf7iF
JFS

190

sizeofएक संकलन-समय ऑपरेटर है , इसलिए संकलन के समय sizeofऔर उसके ऑपरेंड को परिणाम मान द्वारा प्रतिस्थापित किया जाता है। संकार्य है मूल्यांकन नहीं सब पर (जब यह एक चर लंबाई सरणी है को छोड़कर); केवल परिणाम का प्रकार मायने रखता है।

short func(short x) {  // this function never gets called !!
   printf("%d", x);    // this print never happens
   return x;
}

int main() {
   printf("%d", sizeof(func(3))); // all that matters to sizeof is the 
                                  // return type of the function.
   return 0;
}

आउटपुट:

2

के रूप shortमें मेरी मशीन पर 2 बाइट्स रह रहे हैं।

फ़ंक्शन के वापसी प्रकार को बदलना double:

double func(short x) {
// rest all same

8आउटपुट के रूप में दे देंगे ।


12
केवल कभी-कभी - यदि संभव हो तो संकलन समय है।
मार्टिन बेकेट

10
-1, जैसा कि यह कथित (और सही) उत्तर के साथ विरोधाभास में है, और मानक का हवाला नहीं देता है।
सैम होसेवर

1
स्ट्रिंग्स के साथ काम करते समय साइज़ोफ () ऑपरेटर के संकलन-समय के समाधान के लिए एक अच्छा लाभ है। यदि आपके पास एक स्ट्रिंग है जो कि स्ट्रेंथ () का उपयोग करने के बजाय एक उद्धृत स्ट्रिंग के रूप में आरम्भ की जाती है, जहाँ स्ट्रिंग में शामिल वर्ण सरणी को रन-टाइम पर नल-टर्मिनेटर के लिए स्कैन करना पड़ता है, तो आकार (quoted_string) संकलन समय पर जाना जाता है, और इसलिए रन-टाइम पर। यह एक छोटी सी बात है, लेकिन अगर आप उद्धृत स्ट्रिंग का उपयोग लाखों और लाखों बार करते हैं, तो यह प्रदर्शन में एक महत्वपूर्ण अंतर बनाता है।
user2548100

यदि आप वास्तव में एक लूप में लाखों और लाखों बार इसका उपयोग करते हैं, तो क्या यह लूप से बाहर की लंबाई की गणना के लिए बहुत अधिक समझदार नहीं होगा? मुझे निश्चित रूप से उम्मीद है कि आपके पास अपने कोड में लाखों और विभिन्न हार्डकॉस्ट स्थिरांक नहीं हैं। : -ओ
वेकी

47

sizeof(foo) संकलन के समय अभिव्यक्ति के आकार को खोजने के लिए वास्तव में कठिन प्रयास करता है:

6.5.3.4:

आकारऑफ़ ऑपरेटर अपने ऑपरेंड के आकार (बाइट्स में) का उत्पादन करता है, जो एक प्रकार का एक अभिव्यक्ति या कोष्ठक नाम हो सकता है। आकार ऑपरेंड के प्रकार से निर्धारित होता है। परिणाम एक पूर्णांक है। यदि ऑपरेंड का प्रकार एक चर लंबाई सरणी प्रकार है, तो ऑपरेंड का मूल्यांकन किया जाता है; अन्यथा, ऑपरेंड का मूल्यांकन नहीं किया जाता है और परिणाम पूर्णांक स्थिर होता है।

संक्षेप में: परिवर्तनशील लंबाई सरणियाँ, रनटाइम पर चलती हैं। (नोट: परिवर्तनीय लंबाई सरणी एक विशिष्ट विशेषता है - इसके साथ आवंटित सरणियाँ नहीं malloc(3)।) अन्यथा, केवल अभिव्यक्ति का प्रकार गणना की जाती है, और संकलन समय पर।


33

sizeofएक संकलित समय निर्मित ऑपरेटर है और एक फ़ंक्शन नहीं है। यह उन मामलों में बहुत स्पष्ट हो जाता है जब आप इसे बिना कोष्ठक के उपयोग कर सकते हैं:

(sizeof x)  //this also works

1
लेकिन यह सवाल का जवाब कैसे है?
सेबेस्टियन मच

5
@phresnel: यह सिर्फ यह स्पष्ट करने के लिए है कि साइज़ोफ़ "अजीब" है और सामान्य कार्यों के नियमों के अधीन नहीं है। मैंने वैसे भी सामान्य रनटाइम ऑपरेटरों (+) और (-) के साथ संभावित भ्रम को दूर करने के लिए पोस्ट को संपादित किया
hugomg

sizeofऑपरेटर है नहीं एक संकलन समय ऑपरेटर, आप केवल यह एक VLA देने के लिए इस यह पता लगाने की है।
paxdiablo

21

ध्यान दें

यह उत्तर एक डुप्लिकेट से मर्ज किया गया था, जो देर से आने वाली तारीख को स्पष्ट करता है।

मूल

वैरिएबल लेंथ एरे को छोड़कर आकार अपने तर्कों का मूल्यांकन नहीं करता है। हम इसे C99 मानक खंड 6.5.3.4 ड्राफ्टऑफ़ ऑपरेटर पैराग्राफ 2 से देख सकते हैं जो कहता है:

आकारऑफ़ ऑपरेटर अपने ऑपरेंड के आकार (बाइट्स में) का उत्पादन करता है, जो एक प्रकार का एक अभिव्यक्ति या कोष्ठक नाम हो सकता है। आकार ऑपरेंड के प्रकार से निर्धारित होता है। परिणाम एक पूर्णांक है। यदि ऑपरेंड का प्रकार एक चर लंबाई सरणी प्रकार है, तो ऑपरेंड का मूल्यांकन किया जाता है; अन्यथा, ऑपरेंड का मूल्यांकन नहीं किया जाता है और परिणाम पूर्णांक स्थिर होता है।

एक टिप्पणी ( अब हटा दी गई ) ने पूछा कि क्या इस तरह से कुछ रन-टाइम पर मूल्यांकन करेगा:

sizeof( char[x++]  ) ;

और वास्तव में यह होगा, कुछ इस तरह से भी काम करेगा ( उन दोनों को देखें ):

sizeof( char[func()]  ) ;

चूंकि वे दोनों चर लंबाई सरणियाँ हैं। हालाँकि, मैं किसी एक में बहुत अधिक व्यावहारिक उपयोग नहीं देखता हूँ।

ध्यान दें, चर लंबाई सरणियों को C99 मानक सेक्शन ड्राफ्ट में कवर किया गया है। 6.7.5.2 ऐरे घोषणाकर्ता पैरा 4 :

[...] यदि आकार पूर्णांक स्थिर अभिव्यक्ति है और तत्व प्रकार का ज्ञात स्थिर आकार है, तो सरणी प्रकार एक चर लंबाई सरणी प्रकार नहीं है; अन्यथा, सरणी प्रकार एक चर लंबाई सरणी प्रकार है।

अपडेट करें

सी 11 में वीएलए मामले के लिए उत्तर परिवर्तन, कुछ मामलों में यह अनिर्दिष्ट है कि आकार की अभिव्यक्ति का मूल्यांकन किया गया है या नहीं। अनुभाग 6.7.6.2 ऐरे घोषणाकर्ताओं से जो कहते हैं:

[...] जहां एक आकार अभिव्यक्ति एक आकार ऑपरेटर के ऑपरेटर का हिस्सा है और आकार अभिव्यक्ति के मूल्य को बदलने से ऑपरेटर के परिणाम को प्रभावित नहीं होगा, यह अनिर्दिष्ट है कि आकार की अभिव्यक्ति का मूल्यांकन किया गया है या नहीं।

उदाहरण के लिए इस तरह से एक मामले में ( इसे लाइव देखें ):

sizeof( int (*)[x++] )

1
यहां याद रखने वाली महत्वपूर्ण बात यह है कि ज्यादातर समय, sizeofप्रभावी रूप से एक मैक्रो है - यह कोड नहीं बनाता है, लेकिन अपेक्षित मूल्य को प्रीकम्प्यूट करता है और इसे सीधे कोड में जमा करता है। ध्यान दें कि C99 तक यह एकमात्र व्यवहार था , क्योंकि VBA मौजूद नहीं था (मैं वास्तव में इस उत्तर तक उनके बारे में कभी नहीं सुना था, यह विश्वास है या नहीं!)
Corley Brigman

किस तरह से अभिव्यक्ति के मूल्य और नए मूल्य के निर्धारण के अलावा किसी भी चीज़ sizeof (char[x++]);के xलिए मूल्य का उपयोग किया जाएगा , दोनों उस ऑपरेटर के लिए सामान्य हैं? x++x
सुपरकैट

@ जलक ... इर, हां, मेरा मतलब 'वीएलए' से था :) शफीक - वे रनटाइम पर मूल्यांकन क्यों करेंगे? जैसे मैंने कहा, मैंने कभी वीएलएएस नहीं देखा है, लेकिन उन दोनों प्रकार के संकलन समय पर ज्ञात हैं, क्या वे नहीं हैं?
कॉर्ली ब्रिग्मैन

@CorleyBrigman तड़क-भड़क वाला उत्तर होगा b / c मानक ऐसा कहता है, लेकिन इसका कारण b / c है जिसे हम संकलन समय पर सरणी आकार नहीं जानते हैं इसलिए हमें रन-टाइम पर अभिव्यक्ति का मूल्यांकन करना होगा। वीएलएएएस एक दिलचस्प विषय है, यहां दो पोस्ट हैं जो मैंने उन पर यहां और यहां की हैं
शफीक याघमोर

@ शेफिक - आह, ठीक है, मुझे लगता है कि मेरा भ्रम था मुझे नहीं पता था कि वीएलए है char[x++]। यह char*मेरी बेहिसाब आंखों की तरह प्रभावी दिखता है ।
कॉर्ली ब्रिग्मैन

11

जैसा कि sizeofऑपरेटर के संचालन का मूल्यांकन नहीं किया जाता है, आप यह कर सकते हैं:

int f(); //no definition, which means we cannot call it

int main(void) {
        printf("%d", sizeof(f()) );  //no linker error
        return 0;
}

ऑनलाइन डेमो: http://ideone.com/S8e2Y

fयदि आपको sizeofकेवल इसका उपयोग किया जाता है, तो आपको फ़ंक्शन को परिभाषित करने की आवश्यकता नहीं है । इस तकनीक का उपयोग ज्यादातर C ++ टेम्प्लेट मेटाप्रोग्रामिंग में किया जाता है, क्योंकि C ++ में भी, के ऑपरेंड का sizeofमूल्यांकन नहीं किया जाता है।

यह काम क्यों करता है? यह काम करता है क्योंकि sizeofऑपरेटर मूल्य पर काम नहीं करता है , इसके बजाय यह अभिव्यक्ति के प्रकार पर काम करता है । इसलिए जब आप लिखते हैं sizeof(f()), तो यह अभिव्यक्ति के प्रकार पर काम करता है f(), और यह फ़ंक्शन के रिटर्न प्रकार के अलावा कुछ भी नहीं है f। रिटर्न प्रकार हमेशा एक ही होता है, इससे कोई फर्क नहीं पड़ता कि यदि वास्तव में निष्पादित होता है, तो फ़ंक्शन किस मूल्य पर लौटेगा।

C ++ में, आप यह भी कर सकते हैं:

struct A
{
  A(); //no definition, which means we cannot create instance!
  int f(); //no definition, which means we cannot call it
};

int main() {
        std::cout << sizeof(A().f())<< std::endl;
        return 0;
}

फिर भी ऐसा लगता है, जैसे, sizeofमैं पहली बार एक उदाहरण बना रहा हूं A, लिखकर A(), और फिर fउदाहरण पर फ़ंक्शन को कॉल करके , लिखकर A().f(), लेकिन ऐसी कोई बात नहीं होती है।

डेमो: http://ideone.com/egPMi

यहाँ एक और विषय है जो कुछ अन्य दिलचस्प गुणों के बारे में बताता है sizeof:


10

संकलन के दौरान निष्पादन नहीं हो सकता है। तो ++i/ i++नहीं होगा। इसके अलावा sizeof(foo())समारोह निष्पादित नहीं होगा, लेकिन सही प्रकार लौट आते हैं।


2
" निष्पादन संकलन के दौरान नहीं हो सकता है। " आपका क्या मतलब है?
जिज्ञासु

1
संकलन केवल ऑब्जेक्ट कोड बनाएगा ... ऑब्जेक्ट कोड केवल तभी निष्पादित किया जाएगा जब उपयोगकर्ता बाइनरी निष्पादित करता है। जैसा कि आकार में होता है संकलन समय पर यह मान लेना कि i ++ वृद्धि गलत है।
राकेश

" जैसा कि आकार का संकलन समय पर होता है " आपका मतलब है: "जैसा sizeofकि एक संकलन समय स्थिर अभिव्यक्ति है"?
जिज्ञासु

जैसे "# डेफिन" प्री-प्रोसेसिंग के दौरान होता है, उसी तरह साइज़ोफ का संकलन समय पर होगा। संकलन के दौरान सभी प्रकार की जानकारी उपलब्ध है इसलिए आकार का मूल्यांकन किया जाता है और फिर संकलन के दौरान और मूल्य को प्रतिस्थापित किया जाता है। जैसा कि पहले ही @pmg द्वारा "C99 स्टैंडर्ड से" पहले उल्लेख किया गया है।
राकेश

1
" आकार का संकलन समय पर होगा " एक ऐसी चीज के लिए जो एक चर लंबाई सरणी नहीं है
curiousguy

0

sizeofसंकलन-समय पर चलता है, लेकिन x++केवल रन-टाइम पर मूल्यांकन किया जा सकता है। इसे हल करने के लिए, C ++ मानक निर्धारित करता है कि के ऑपरेंड का sizeofमूल्यांकन नहीं किया गया है। सी मानक कहते हैं:

यदि ऑपरेंड का प्रकार [का sizeof] एक चर लंबाई सरणी प्रकार है, तो ऑपरेंड का मूल्यांकन किया जाता है; अन्यथा, ऑपरेंड का मूल्यांकन नहीं किया जाता है और परिणाम पूर्णांक स्थिर होता है।


C ++ में कोई VLA नहीं है।
एलएफ

-2

sizeof() ऑपरेटर केवल डेटा-प्रकार का आकार देता है, यह आंतरिक तत्वों का मूल्यांकन नहीं करता है।


यह गलत है, sizeof()ऑपरेटर पुनरावर्ती कार्य करता है, और एक कंटेनर के सभी तत्वों के बाइट्स में आकार प्राप्त करेगा, एक वर्ग या संरचना के सदस्य, आदि। आप कुछ सदस्यों के साथ एक साधारण वर्ग बनाकर खुद को यह आसानी से साबित कर सकते हैं और इस पर फोन sizeof()कर रहे हैं। (हालाँकि, वहाँ कुछ भी जो कि एक ऐसा पॉइंटर है, जो इसका आकार नहीं देख सकता है - सिर्फ़ पॉइंटर का आकार।) यह सब संकलन समय पर होता है, जैसा कि अन्य टिप्पणीकारों ने कहा: अंदर के भावों का sizeof()मूल्यांकन नहीं किया जाता है।
टायलर शेलबर्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.