आप सी "एक परिभाषा शासन" का उल्लंघन कर रहे है, और परिणाम अपरिभाषित व्यवहार है।मानक में "एक परिभाषा नियम" औपचारिक रूप से नहीं बताया गया है। हम विभिन्न स्रोत फ़ाइलों (उर्फ, अनुवाद इकाइयों) में वस्तुओं को देख रहे हैं, इसलिए हम "बाहरी परिभाषाओं" से चिंतित हैं। "एक बाहरी परिभाषा" अर्थ (सी 11 6.9 पी 5) से बताया जाता है:
एक बाहरी परिभाषा एक बाहरी घोषणा भी एक समारोह (एक इनलाइन परिभाषा के अलावा अन्य) या किसी वस्तु की एक परिभाषा है। यदि बाहरी लिंकेज के साथ घोषित एक पहचानकर्ता को अभिव्यक्ति में उपयोग किया जाता है (sizeof
या _Alignof
ऑपरेटर के ऑपरेशन के हिस्से के अलावा जिसका परिणाम एक पूर्णांक स्थिरांक है), पूरे कार्यक्रम में कहीं पहचानकर्ता के लिए बिल्कुल एक बाहरी परिभाषा होगी; अन्यथा, एक से अधिक नहीं होगा।
कौन सा मूल रूप से मतलब है कि आप केवल करने की अनुमति है सबसे एक बार पर एक वस्तु को परिभाषित। (अन्यथा खंड आप बिल्कुल एक बाहरी वस्तु को परिभाषित नहीं करने के लिए अगर यह कार्यक्रम में कहीं भी इस्तेमाल कभी नहीं किया है की अनुमति देता है।)
नोट आप b
के लिए दो बाहरी परिभाषाओं है। एक संरचना है कि आप foo.c
में प्रारंभ है, और अन्य main.c
में जांच परिभाषा, (सी 11 6.9.2 p1-2) है:
तो एक वस्तु के लिए एक पहचानकर्ता की घोषणा फ़ाइल गुंजाइश है और एक प्रारंभकर्ता, घोषणा पहचानकर्ता के लिए बाहरी परिभाषा है।
एक वस्तु एक प्रारंभकर्ता बिना गुंजाइश फ़ाइल है कि के लिए एक पहचानकर्ता के एक घोषणा, और एक भंडारण-वर्ग विनिर्देशन के बिना या भंडारण-वर्ग विनिर्देशक static
के साथ, एक जांच परिभाषा का गठन किया। यदि किसी अनुवाद इकाई में पहचानकर्ता के लिए एक या अधिक टेटेटिव परिभाषाएं होती हैं, और अनुवाद इकाई में उस पहचानकर्ता के लिए कोई बाहरी परिभाषा नहीं होती है, तो व्यवहार बिल्कुल वैसा ही होता है जैसे अनुवाद इकाई में उस पहचानकर्ता की फ़ाइल स्कोप घोषणा होती है, समग्र प्रकार के साथ अनुवाद इकाई के अंत में, 0.
के बराबर प्रारंभिक के साथ तो आपके पास b
की कई परिभाषाएं हैं। हालांकि, एक और त्रुटि है, जिसमें आपने b
को विभिन्न प्रकार के साथ परिभाषित किया है। सबसे पहले ध्यान दें कि बाहरी लिंक के साथ एक ही ऑब्जेक्ट में कई घोषणाओं की अनुमति है।
अनुवाद इकाइयों और पुस्तकालयों के सेट है कि एक पूरे कार्यक्रम का गठन किया, प्रत्येक: हालांकि, जब एक ही नाम दो अलग-अलग स्रोत फ़ाइलों में प्रयोग किया जाता है, उस नाम एक ही वस्तु (सी 11 6.2.2 p2) को संदर्भित करता है बाहरी लिंकेज के साथ एक विशेष पहचानकर्ता की घोषणा एक ही ऑब्जेक्ट या फ़ंक्शन को दर्शाती है।
सी एक ही वस्तु के लिए घोषणाओं पर एक सख्त सीमा डालता है (C11 6.2.7 p2):
सभी घोषणाओं है कि एक ही वस्तु या समारोह का उल्लेख संगत प्रकार जाएगा; अन्यथा, व्यवहार अपरिभाषित है।
चूंकि आपकी प्रत्येक स्रोत फ़ाइलों में b
के प्रकार वास्तव में मेल नहीं खाते हैं, व्यवहार अपरिभाषित है। (क्या एक संगत प्रकार C11 6.2.7 के सभी में विस्तार से वर्णन किया गया है का गठन किया है, लेकिन यह मूल रूप से किया जा रहा है कि प्रकार से मेल करने के लिए निर्भर करता है।)
तो तुम b
के लिए दो असफलताओं है:
- एकाधिक परिभाषाएं।
- असंगत प्रकारों के साथ एकाधिक घोषणाएं।
तकनीकी रूप से, आपकी दोनों स्रोत फ़ाइलों में int a
की आपकी घोषणा "एक परिभाषा नियम" का भी उल्लंघन करती है। नोट a
बाहरी लिंकेज (C11 6.2.2 पी 5) है:
एक वस्तु के लिए एक पहचानकर्ता की घोषणा गुंजाइश और बिना किसी संग्रहण-वर्ग विनिर्देशन फ़ाइल नहीं है तो उसके संबंध बाहरी है।
लेकिन, C11 6.9.2 पहले से बोली से, उन int a
जांच परिभाषाओं बाहरी परिभाषाएं दी गई हैं, और आप केवल शीर्ष पर सी 11 6.9 से बोली से उन में से एक की अनुमति है।
सामान्य अस्वीकरण अपरिभाषित व्यवहार के लिए आवेदन करते हैं। कुछ भी हो सकता है, और इसमें आपके द्वारा देखे गए व्यवहार को शामिल किया जाएगा।
सेल्सियस के लिए एक आम विस्तार कई बाहरी परिभाषाओं अनुमति देने के लिए है, और सूचनात्मक अनुलग्नक J.5 (सी 11 J.5.11) में सी मानक में वर्णित है:
वहाँ अधिक हो सकता है कीवर्ड extern
के स्पष्ट उपयोग के बिना किसी ऑब्जेक्ट के पहचानकर्ता के लिए एक बाहरी परिभाषा से, या ; यदि परिभाषाएं से असहमत हैं, या एक से अधिक प्रारंभिक हैं, व्यवहार (6.9.2) को अपरिभाषित है।
(जोर मेरा है।) के बाद से a
की परिभाषा दी गई सहमति व्यक्त करते हैं, वहाँ कोई नुकसान नहीं है, लेकिन b
के लिए परिभाषाएँ सहमत नहीं हूं। यह एक्सटेंशन बताता है कि आपका कंपाइलर एकाधिक परिभाषाओं की उपस्थिति के बारे में शिकायत क्यों नहीं करता है। सी 11 6.2.2 के उद्धरण से, लिंकर एक ही ऑब्जेक्ट के एकाधिक संदर्भों को मेल करने का प्रयास करेगा।
Linkers आमतौर पर एकाधिक अनुवाद इकाइयों में एक ही प्रतीक की कई परिभाषाएं मिलान के लिए दो मॉडलों में से एक का उपयोग करें। ये "सामान्य मॉडल" और "रेफरी/डीफ़ मॉडल" हैं। "सामान्य मॉडल" में, एक ही नाम वाले एकाधिक ऑब्जेक्ट्स को एक ही ऑब्जेक्ट में union
शैली तरीके से तब्दील किया जाता है ताकि ऑब्जेक्ट सबसे बड़ी परिभाषा के आकार पर हो। "रेफरी/डीफ़ मॉडल" में, प्रत्येक बाहरी नाम में बिल्कुल एक परिभाषा होनी चाहिए।
जीएनयू टूलचेन डिफ़ॉल्ट रूप से "सामान्य मॉडल" का उपयोग करता है, और "आराम से रेफरी/डीफ़ मॉडल", जहां यह एक एकल अनुवाद इकाई के लिए सख्ती से एक परिभाषा नियम लागू करता है, लेकिन एकाधिक अनुवाद इकाइयों में उल्लंघन के बारे में शिकायत नहीं करता है ।
-fno-common
विकल्प का उपयोग कर जीएनयू कंपाइलर में "सामान्य मॉडल" को दबाया जा सकता है।
$ cat a.c
#include <stdio.h>
int a;
struct { char a; int b; } b = { 2, 4 };
void foo() { printf("%zu\n", sizeof(b)); }
$ cat b.c
#include <stdio.h>
extern void foo();
int a, b;
int main() { printf("%zu\n", sizeof(b)); foo(); }
$ gcc -fno-common a.c b.c
/tmp/ccd4fSOL.o:(.bss+0x0): multiple definition of `a'
/tmp/ccMoQ72v.o:(.bss+0x0): first defined here
/tmp/ccd4fSOL.o:(.bss+0x4): multiple definition of `b'
/tmp/ccMoQ72v.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `b' changed from 8 in /tmp/ccMoQ72v.o to 4 in /tmp/ccd4fSOL.o
collect2: ld returned 1 exit status
$
मैं व्यक्तिगत रूप से लिंकर द्वारा जारी किए गए पिछले चेतावनी लग रहा है हमेशा संकल्प की परवाह किए बिना प्रदान की जानी चाहिए: जब मैं अपने सिस्टम पर इस परीक्षण किया है, यह आपसे मिलते-जुलते कोड के लिए कारण होता है "सख्त रेफरी/डेफ मॉडल" व्यवहार एकाधिक ऑब्जेक्ट परिभाषाओं के लिए मॉडल, लेकिन यह न तो यहां और न ही वहां है।
संदर्भ:
Unfortunately, I can't give you the link to my copy of the C11 Standard
What are extern
variables in C?
The "Beginner's Guide to Linkers"
SAS Documentation on External Variable Models
आपका प्रश्न क्या है? –
मुद्रण पॉइंटर्स के लिए '% p' का उपयोग करें, आपको अपने शीर्षलेख में 'foo' जोड़ना चाहिए। – Nobilis
यदि आप संघर्ष को हल करना चाहते हैं, तो विभिन्न स्थिर घोषित करें। – snf