इंट (*) का अर्थ (इंट *) = 5 (या कोई पूर्णांक मान)


88

मैं इसका पता नहीं लगा सकता:

int main() {
    int (*) (int *) = 5;
    return 0;
}

उपरोक्त असाइनमेंट g ++ c ++ 11 के साथ संकलित है। मुझे पता है कि int (*) (int *)यह एक फ़ंक्शन के लिए एक संकेतक है जो एक (int *)तर्क के रूप में स्वीकार करता है और एक इंट रिटर्न देता है, लेकिन मुझे समझ में नहीं आता है कि आप इसे 5 से कैसे बराबरी कर सकते हैं। सबसे पहले मैंने सोचा था कि यह एक ऐसा फ़ंक्शन है जो लगातार 5 (मेरे हाल के सीखने से) में लौटता है एफ #, शायद, हाहा), तो मैंने सोचा, संक्षेप में, कि फ़ंक्शन पॉइंटर मेमोरी लोकेशन 5 को इंगित करता है, लेकिन यह काम नहीं करता है, स्पष्ट रूप से, और न ही हेक्स मान।

यह सोचते हुए कि यह हो सकता है क्योंकि फ़ंक्शन एक इंट लौटाता है, और एक इंट असाइन करना ठीक है (किसी तरह), मैंने यह भी कोशिश की:

int * (*) (int *) = my_ptr

जहां my_ptrप्रकार है int *, इस प्रकार के दूसरे फ़ंक्शन पॉइंटर के रूप में, जैसा कि पहले मामले में टाइप इंट के साथ है। यह संकलन नहीं है। इसके बजाय, 5 या किसी भी इंट वैल्यू my_ptrको इस फंक्शन पॉइंटर के लिए संकलित नहीं करता है।

तो असाइनमेंट का क्या मतलब है?

अपडेट १

हमारे पास पुष्टि है कि यह एक बग है, जैसा कि सबसे अच्छा उत्तर में दिखाया गया है। हालाँकि, यह अभी भी ज्ञात नहीं है कि वास्तव में क्या होता है जो आप फ़ंक्शन पॉइंटर को असाइन करते हैं, या असाइनमेंट के साथ क्या होता है। उस पर कोई (अच्छा) स्पष्टीकरण बहुत सराहना की जाएगी! कृपया समस्या पर अधिक स्पष्टता के लिए नीचे दिए गए संपादन देखें।

संपादित करें 1

मैं gcc संस्करण का उपयोग कर रहा हूँ 4.8.2 (Ubuntu 4.8.2 में)

संपादित करें २

वास्तव में, यह कुछ भी करने के लिए मेरे संकलक पर काम करता है। यहां तक ​​कि इसे एक एसटीडी :: स्ट्रिंग चर या एक फ़ंक्शन नाम के बराबर, जो एक डबल लौटाता है, काम करता है।

2.1 संपादित करें

दिलचस्प बात यह है कि इसे किसी भी फ़ंक्शन के लिए एक फ़ंक्शन पॉइंटर बनाते हैं जो एक डेटा प्रकार देता है जो पॉइंटर नहीं है, इसे संकलित करने देगा, जैसे कि

std::string (*) () = 5.6;

लेकिन जैसे ही फंक्शन पॉइंटर एक ऐसे फंक्शन के लिए होता है जो कुछ पॉइंटर लौटाता है, वह कंपाइल नहीं करता, जैसे कि

some_data_type ** (*) () = any_value;

3
हम्म ... यह सही नहीं लगता है, और क्लैंग इसे स्वीकार नहीं करता है। एक gcc एक्सटेंशन (या बग) हो सकता है।
विंटरम्यूट

4
g ++ संकलन करता है, लेकिन काम नहीं कर रहा है:error: expected identifier or '(' before ')' token
tivn

3
@ 0x499602D ध्यान दें कि कोड पॉइंटर को कोई नाम नहीं देता है। इसके साथ int *x = 5आपने नाम रखा x। इसके साथ int * (*x) (int *) = 5संकलन नहीं होगा। (यद्यपि जो C कोड के रूप में संकलित होगा)।
nos

5
कम किया गया टेस्टकेस: int(*) = 5;औरint(*);
जोहान्स शाउब -

जवाबों:


60

यह g ++ में बग है।

 int (*) (int *) 

एक प्रकार का नाम है।

C ++ में आपके पास एक पहचानकर्ता के बिना एक प्रकार के नाम के साथ घोषणा नहीं हो सकती है।

तो यह जी ++ के साथ संकलित करता है।

 int (*) (int *) = 5;

और यह संकलन:

 int (*) (int *);

लेकिन वे दोनों अमान्य घोषणाएँ हैं।

संपादित करें :

टीसी एक समान परीक्षण मामले के साथ बगज़िला बग 60680 टिप्पणियों में उल्लेख करता है लेकिन इसे अभी तक अनुमोदित नहीं किया गया है । बगज़िला में बग की पुष्टि की जाती है।

EDIT2 :

जब ऊपर की दो घोषणाएँ फ़ाइल स्कोप g ++ पर हों तो सही तरीके से डायग्नोस्टिक जारी करता है (यह ब्लॉक स्कोप पर डायग्नोस्टिक जारी करने में विफल रहता है)।

EDIT3 :

मैंने जाँच की और मैं g ++ संस्करण 4 (4.9.2), नवीनतम पूर्व-रिलीज़ संस्करण 5 (5.0.1 20150412) और नवीनतम प्रयोगात्मक संस्करण 6 (6.0.0 20150412) की नवीनतम रिलीज़ पर समस्या को पुन: उत्पन्न कर सकता हूं।


5
MSVC ने संपादित पोस्ट कोड को अस्वीकार कर दियाerror C2059: syntax error : ')'
वेदर वेन

यदि यह एक प्रकार का नाम है, तो 'int (*) (int *) int_func क्यों नहीं है;' काम?
कोनराड कप्प

1
जीसीसी बगज़िला के लिए, "न्यू" एक पुष्ट बग है। (अपुष्ट कीड़े "UNCONFIRMED" हैं)।
टीसी

4
@KonradKapp: यदि आप कहते हैं कि यह ठीक काम करता है, int (*int_func)(int *); जो एक फ़ंक्शन पॉइंटर नामित करता है int_func
एडवर्ड

3
@KonradKapp C ++ पहचानकर्ता को रखने के लिए infix संकेतन का उपयोग करता है; इसी कारण यह है int x[5];और नहींint[5] x;
एम.एम.

28

यह मान्य नहीं है C ++। याद रखें कि क्योंकि आपके विशेष संकलक को संकलित करने के लिए होता है, यह इसे वैध नहीं बनाता है। कंपाइलर, सभी जटिल सॉफ़्टवेयरों की तरह, कभी-कभी बग होते हैं और यह एक प्रतीत होता है।

इसके विपरीत clang++शिकायतें:

funnycast.cpp:3:11: error: expected expression
    int (*) (int *) = 5;
          ^
funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction
    int (*) (int *) = 5;
             ~~~ ^
funnycast.cpp:3:19: error: expected expression
    int (*) (int *) = 5;
                  ^
3 errors generated.

यह अपेक्षित व्यवहार है क्योंकि अपमानजनक रेखा C ++ मान्य नहीं है। यह एक असाइनमेंट होने के कारण (क्योंकि =) में कोई पहचानकर्ता नहीं है।


9

जैसा कि अन्य उत्तरों ने बताया है, यह एक बग है

int (*) (int *) = 5;

संकलित करता है। इस कथन का एक उचित अनुमान है कि एक अर्थ होने की उम्मीद की जाएगी:

int (*proc)(int*) = (int (*)(int*))(5);

अब procएक पॉइंटर-टू-फंक्शन है जो 5किसी भी फ़ंक्शन के आधार पते के पते की अपेक्षा करता है जो ए लेता है int*और रिटर्न देता है int

कुछ माइक्रोकंट्रोलर / माइक्रोप्रोसेसरों पर 5एक मान्य कोड पता हो सकता है, और वहां इस तरह के फ़ंक्शन का पता लगाना संभव हो सकता है।

अधिकांश सामान्य-उद्देश्य वाले कंप्यूटरों पर, पॉइंटर एक्सेस 0-1023को पकड़ने के लिए मेमोरी का पहला पेज ( 4K पेजों के पते ) जानबूझकर अमान्य (अनमैपेड) होते हैं null

इस प्रकार, जब व्यवहार प्लेटफ़ॉर्म पर निर्भर करता है, तो किसी को एक पृष्ठ गलती की उम्मीद की जा सकती है जब *procइसे लागू किया जाता है (जैसे, (*proc)(&v))। जिस समय *procका आह्वान किया जाता है, उससे पहले कुछ भी असामान्य नहीं होता है।

जब तक आप एक गतिशील लिंकर नहीं लिख रहे हैं, तब तक आपको लगभग निश्चित रूप से पतों की गणना नहीं करनी चाहिए और उन्हें पॉइंटर-टू-फंक्शन चर पर असाइन करना चाहिए।


2
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp

यह कमांड लाइन बहुत सारी इंटरमीडिएट फाइलें बनाती है। उनमें से पहला so.cpp.170r.expand, कहता है:

...
int main() ()
{
  int D.2229;
  int _1;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  _1 = 0;
;;    succ:       3

;;   basic block 3, loop depth 0
;;    pred:       2
<L0>:
  return _1;
;;    succ:       EXIT

}
...

यह अभी भी जवाब नहीं देता है कि वास्तव में क्या होता है, लेकिन यह सही दिशा में एक कदम होना चाहिए।


दिलचस्प। इन मध्यवर्ती फ़ाइलों का उद्देश्य क्या है?
कोनराड कप्प

@KonradKapp मानव कोड से मशीन कोड का उत्पादन करने के लिए काफी जटिल प्रक्रिया है (खासकर यदि आप चाहते हैं कि आपका कंपाइलर इसके आउटपुट का अनुकूलन करे)। चूंकि संकलन इतना जटिल है, यह एक चरण में नहीं किया जाता है, अधिकांश संकलक में मध्यवर्ती प्रतिनिधि (आईआर) के कुछ रूप हैं।
11684

2
IR होने का दूसरा कारण यह है कि यदि आपके पास एक अच्छी तरह से परिभाषित IR है तो आप अपने कंपाइलर के फ्रंट-एंड और बैक-एंड को अलग कर सकते हैं। (जैसे फ्रंट-एंड-सी आपके आईआर को संकलित करता है, बैक-एंड आईआर को इंटेल मशीन कोड के लिए संकलित करता है। अब यदि आप एआरएम सपोर्ट को जोड़ना चाहते हैं तो आपको केवल दूसरे बैक-एंड की आवश्यकता है। और यदि आप गो को संकलित करना चाहते हैं, तो आपको केवल एक की आवश्यकता है। दूसरा फ्रंट-एंड, और उसके शीर्ष पर गो कंपाइलर इंटेल और एआरएम दोनों का तुरंत समर्थन करता है क्योंकि आप दोनों बैक-एंड का पुनः उपयोग कर सकते हैं।
11684

@ 11684 ठीक है, समझ में आता है। बहुत ही रोचक। मैं यह निर्धारित नहीं कर सका कि रोलांड ने इस जवाब में क्या भाषा दी है ... यह सी के साथ मिश्रित विधानसभा के कुछ प्रकार की तरह दिखता है
कोनराड कप्प

आईआर मुद्रण योग्य नहीं होना चाहिए; मुझे नहीं पता कि जीसीसी क्या उपयोग करता है, यह केवल एक मुद्रण योग्य प्रतिनिधित्व हो सकता है @KonradKapp
11684
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.