C ++ कंपाइलर एक बाहरी चर कैसे खोजते हैं?


15

मैं इस प्रोग्राम को g ++ और clang ++ द्वारा संकलित करता हूं। एक अंतर है:
जी ++ प्रिंट 1, लेकिन क्लैंग ++ प्रिंट्स 2.
ऐसा लगता है कि
जी ++: एक्सटर्नल वेरिएबल को सबसे कम दायरे में परिभाषित किया गया है।
क्लैंग ++: एक्सटर्नल वेरिएबल को सबसे कम वैश्विक दायरे में परिभाषित किया गया है।

क्या सी ++ के बारे में कोई विनिर्देश है?

main.cpp

#include <iostream>
static int i;
static int *p = &i;

int main() {
  int i;
  {
    extern int i;
    i = 1;
    *p = 2;
    std::cout << i << std::endl;
  }
}

other.cpp

int i;

संस्करण: g ++: 7.4.0 / clang ++: 10.0.0
संकलन: $ (CXX) main.cpp other.cpp -oExo.exe


4
कंपाइलर बाहरी के साथ कुछ भी नहीं करता है सिवाय उनके जो बाहरी संदर्भ वाले चर के रूप में चिह्नित करते हैं, लिंकर वह है जो सभी संकलित ऑब्जेक्ट फ़ाइलों के बीच लिंक को हल करने का प्रयास करता है।
SPlatten

एक उत्कृष्ट (यदि अजीब) सवाल! ( MSVCऔर clang-clदोनों देते हैं 2) में अपने कोड के साथ खेलना , ऐसा लगता है कि extern int iदोनों द्वारा पूरी तरह से अनदेखा किया गया है: भले ही मैं other.cppफ़ाइल में लिंक नहीं करता हूं , प्रोग्राम बनाता है और चलता है।
एड्रियन मोल

1
@SPlatten संभवतः, लिंकर को संदर्भ को 'हल' करने की आवश्यकता नहीं है i, यह कोशिश नहीं करता है।
एड्रियन मोल

3
संबंधित पुराने निलंबित जीसीसी बग यहां पाया जा सकता है और इसी तरह का खुला क्लैंग बग यहां
अखरोट

जवाबों:


11

[basic.link/7] मानक का प्रासंगिक हिस्सा होना चाहिए। वर्तमान मसौदे में, यह कहता है:

ब्लॉक स्कोप में घोषित एक फंक्शन का नाम और एक ब्लॉक स्कोप externडिक्लेरेशन द्वारा घोषित चर का नाम लिंकेज है। यदि इस तरह की घोषणा एक नामित मॉड्यूल से जुड़ी हुई है, तो कार्यक्रम बीमार है। यदि लिंकेज के साथ एक इकाई की एक दृश्यमान घोषणा है, तो नामस्थान क्षेत्र को घेरने वाली अंतरिम सीमा के बाहर घोषित संस्थाओं की अनदेखी करना, जैसे कि ब्लॉक घोषणा घोषणा एक (संभवतः बीमार) पुनर्वितरण होगी यदि दोनों घोषणाएं समान घोषणा क्षेत्र में दिखाई देती हैं, तो ब्लॉक स्कोप घोषणापत्र घोषित करता है कि एक ही इकाई और पिछले घोषणा के लिंकेज को प्राप्त करता है। यदि ऐसी एक से अधिक मिलान इकाई है, तो प्रोग्राम बीमार है। अन्यथा, यदि कोई मिलान इकाई नहीं मिलती है, तो ब्लॉक स्कोप इकाई बाहरी लिंकेज प्राप्त करती है।यदि, अनुवाद इकाई के भीतर, एक ही इकाई को आंतरिक और बाहरी दोनों प्रकार के लिंकेज के साथ घोषित किया जाता है, तो कार्यक्रम बीमार है।

ध्यान दें कि बाद का उदाहरण आपके मामले से लगभग मेल खाता है:

static void f();
extern "C" void h();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  extern void h();              // C language linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}

तो, कार्यक्रम को बीमार होना चाहिए। व्याख्या उदाहरण के नीचे है:

लाइन # 2 पर घोषणा के बिना, लाइन # 3 पर घोषणा लाइन # 1 पर घोषणा के साथ जुड़ेगी। क्योंकि आंतरिक लिंकेज के साथ घोषणा छिपी हुई है, हालांकि, # 3 को बाहरी लिंकेज दिया जाता है, जिससे कार्यक्रम बीमार हो जाता है।


उदाहरण में कार्यक्रम बीमार का गठन बाहरी लिंकेज के साथ नहीं, मैं क्योंकि वहाँ है परिभाषित कहीं भी। ओपी के उदाहरण के साथ ऐसा नहीं है।
एन। 'सर्वनाम' मी।

3
@ n.'pronouns'm। लेकिन नियम एक अनुवाद इकाई पर लागू होता है: यदि, अनुवाद इकाई के भीतर, एक ही इकाई को आंतरिक और बाहरी दोनों प्रकार के लिंकेज के साथ घोषित किया जाता है, तो कार्यक्रम बीमार है।
डेनियल लैंगर

2
इसका उत्तर केवल C ++ 17 और बाद में लागू होता है, CWG समस्या 426 का समाधान देखें । मुझे लगता है कि उस बदलाव से पहले जीसीसी सही था।
अखरोट

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