2016-02-06 2 views
24

मैं labels as values के साथ खेल रहा था और इस कोड के साथ समाप्त हुआ।'goto * foo' जहां foo एक सूचक नहीं है। यह क्या है?

int foo = 0; 
goto *foo; 

मेरे C/C++ अनुभव मुझसे कहता है *foo मतलब है dereference foo और इस संकलन नहीं करेगा क्योंकि foo एक सूचक नहीं है। लेकिन यह संकलित करता है। यह वास्तव में क्या करता है?

gcc (Ubuntu 4.9.2-0ubuntu1~12.04) 4.9.2, यदि महत्वपूर्ण हो तो।

+2

यह एक ज्ञात बग है। मेरा अद्यतन उत्तर देखें। –

उत्तर

23

यह जीसीसी में एक ज्ञात बग है।

जीसीसी एक documented extension कि प्रपत्र

goto *ptr; 

जहां ptr प्रकार void* के किसी भी अभिव्यक्ति हो सकती है का एक बयान परमिट है। इस एक्सटेंशन के हिस्से के रूप में, एक लेबल नाम पर एक unary && लागू करने से लेबल का पता void* टाइप करता है।

अपने उदाहरण में:

int foo = 0; 
goto *foo; 

foo स्पष्ट रूप से के प्रकार void* नहीं, प्रकार int की है। एक int मूल्य void* में परिवर्तित किया जा सकता है, लेकिन केवल एक स्पष्ट कलाकार के साथ (एक शून्य सूचक स्थिर के विशेष मामले को छोड़कर, जो यहां लागू नहीं होता है)।

अभिव्यक्ति *foo स्वयं ही एक त्रुटि के रूप में सही ढंग से निदान किया गया है। और यह:

goto *42; 

त्रुटि के बिना संकलित (उत्पन्न मशीन कोड एक कूद 42 संबोधित करने के लिए, अगर मैं विधानसभा कोड सही ढंग से पढ़ रहा हूँ प्रतीत होता है)।

एक त्वरित प्रयोग इंगित करता है कि जीसीसी के लिए

goto *42; 

एक ही विधानसभा कोड

goto *(void*)42; 

बाद दस्तावेज विस्तार के सही उपयोग है के लिए के रूप में यह होता है उत्पन्न करता है, और यह आप क्या करना चाहिए है शायद अगर, किसी कारण से, आप पता 42

मैं सबमिट करने के बाद जाने के लिए चाहते हैं एक bug report - जो जल्दी से 012 के डुप्लिकेट के रूप बंद हो गया, 2007 में प्रस्तुत किया गया।

+0

क्या यह 'foo' पता पर कूदने जैसा ही है? –

+1

@ Ælex: यह 'foo' के पते पर नहीं जाता है; यह 'foo' में निहित पते पर कूदता है। –

+0

एक 'शून्य * 'का निर्धारण करना एक int को dereferencing से अधिक" सही "नहीं है ... – Leushenko

6

एक जीसीसी बग माना जाता है। तुलना के रूप में यहां एक क्लैंग आउटपुट है। ऐसा लगता है कि ये त्रुटियां हैं जिनकी हमें उम्मीद करनी चाहिए।

$ cc -v 
Apple LLVM version 7.0.2 (clang-700.1.81) 
Target: x86_64-apple-darwin15.3.0 
Thread model: posix 
$ cc goto.c 
goto.c:5:7: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *' [-Wint-conversion] 
     goto *foo; 
      ^~~~ 
goto.c:5:2: error: indirect goto in function with no address-of-label expressions 
     goto *foo; 
     ^
1 warning and 1 error generated. 

goto.c स्रोत कोड:

int main(int argc, char const *argv[]) 
{ 
    int foo = 0; 
    goto *foo; 
} 
0

यह एक बग, बल्कि GCC's Labels and Values extension का परिणाम नहीं है। मुझे लगता है कि उनके पास तेजी से कूदने वाली टेबल और जेआईटी की तरह चीजें थीं।इस (गलत) सुविधा के साथ, आप कर सकते हैं कार्यों

// c 
goto *(int *)exit; 
// c++ 
goto *reinterpret_cast<int *>(std::exit); 

और एक स्ट्रिंग शाब्दिक में कूद की तरह शानदार स्वादिष्ट चीजें करते

goto *&"\xe8\r\0\0\0Hello, World!Yj\1[j\rZj\4X\xcd\x80,\f\xcd\x80"; 

Try it online!

मत भूलना में कूद उस सूचक अंकगणित की अनुमति है!

goto *(24*(a==1)+"\xe8\7\0\0\0Hello, Yj\1[j\7Zj\4X\xcd\x80\xe8\6\0\0\0World!Yj\1[j\6Zj\4X\xcd\x80,\5\xcd\x80"); 

मैं (आदि argv[0], __FILE__, __DATE__,) पाठक के लिए एक व्यायाम के रूप में अतिरिक्त परिणाम छोड़ देंगे

ध्यान दें कि आप यह सुनिश्चित करना है कि आप के क्षेत्र के लिए निष्पादन योग्य अनुमति है की आवश्यकता होगी स्मृति जो आप कूदते हैं।

+1

वास्तव में यह एक बग है। इसे 'गोटो * पीआरटी' की अनुमति देने के लिए दस्तावेज किया गया है, जहां 'ptr' प्रकार' void * 'है। 'goto * foo; 'जहां' foo' प्रकार 'int *' है, जीसीसी के विस्तार के अपने दस्तावेज़ का उल्लंघन करता है। [मेरा उत्तर] देखें (https://stackoverflow.com/a/35237062/827263) और [यह बग रिपोर्ट] (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=32122)। –

+0

@ किथ थॉम्पसन मैं देखता हूं कि दस्तावेज़ीकरण कहां निर्दिष्ट करता है कि किसी लेबल के पते में 'शून्य *' टाइप किया गया है, लेकिन यह कहां निर्दिष्ट करता है कि 'गोटो *' के गैर-शून्य * 'तर्कों की अनुमति नहीं है? – ceilingcat

+0

"उदाहरण के लिए,' goto * ptr; ' प्रकार 'void *' की किसी भी अभिव्यक्ति की अनुमति है।" –

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