2013-02-22 7 views
9

मुझे यकीन है कि मैं पागल हो रहा हूँ, लेकिन पर विचार निम्नलिखित सी कोड हूँ:बाहरी वैकल्पिक है?

// file1.c 
int first; 

void f(void) 
{ first = 2; } 

// file2.c 
#include <stdio.h> 

int first; 
void f(); 
int main(void) 
{ 
    first = 1; 
    f(); 
    printf("%d", first); 
} 

इन दो फाइलें, किसी कारण एक साथ संकलन और लिंक होगा, और प्रिंट 2 के लिए। मैं हमेशा इस धारणा के तहत था कि जब तक मैंने first की extern के साथ एक या दूसरी (लेकिन दोनों नहीं) परिभाषाओं को लेबल किया, तो यह संकलित नहीं होगा, और वास्तव में extern का पूरा बिंदु था!

+0

जब आप बाहरी रूप में फ़ंक्शन घोषित करते हैं, तो लिंकर इसे अन्य ऑब्जेक्ट्स में खोजेगा। अन्यथा यह उसी फाइल में इसकी तलाश करेगा। – kofemann

+0

यह लिंक भी नहीं करना चाहिए। क्या आप वाकई सभी कंपाइलर और लिंकर चेतावनियां दिखा रहे हैं? –

+0

@KerrekSB लिंक जीसीसी के साथ पूरी तरह ठीक है। 'F' और' main' दोनों से प्रिंटिंग '& first' एक ही पता उत्पन्न करता है। –

उत्तर

5

सामान्य परिस्थितियों के अंतर्गत (बिना किसी अतिरिक्त जीसीसी झंडे) आप के रूप में इस कोड को संकलित करने के लिए ठीक होना चाहिए:

gcc file1.c file2.c 

क्या होने जा रहा है संकलक आप दो वैश्विक चर है कि देखेंगे एक ही चीज़ का नाम दिया और न ही शुरू किया गया है। फिर यह कोड ** कोड के "सामान्य" खंड में आपके अनियमित वैश्विक चर रखेगा। दूसरे शब्दों में यह "पहले" चर की केवल 1 प्रतिलिपि होगी। यह इसलिए होता है क्योंकि gcc के लिए डिफ़ॉल्ट -fcommon

है आप -fno-common ध्वज के साथ संकलित करने के लिए अब आप त्रुटि आप के बारे में सोच रहे थे प्राप्त होता थे, तो:

/tmp/ccZNeN8c.o:(.bss+0x0): multiple definition of `first' 
/tmp/cc09s2r7.o:(.bss+0x0): first defined here 
collect2: ld returned 1 exit status 

इसके समाधान के लिए आप के लिए extern जोड़ेंगे सभी चरों में से एक है।

चेतावनी:
अब मान लीजिए कि आप विभिन्न आकार के दो वैश्विक अप्रारंभीकृत सरणियों था करते हैं:

// file1.c 
int first[10]; 

// file2.c 
int first[20]; 

खैर लगता है क्या, उन्हें gcc -Wall file1.c file2.c साथ संकलन कोई चेतावनी या त्रुटियों और चर का उत्पादन हालांकि यह अलग-अलग आकार का था, हालांकि यह अलग-अलग आकार का था !!!

//objdump from file1.c: 
0000000000000028  O *COM* 0000000000000020 first 

//objdump from file2.c: 
0000000000000050  O *COM* 0000000000000020 first 

यह वैश्विक चर के खतरों में से एक है।


** आप * ओ फ़ाइलों की objdump को देखें, तो (आप gcc -c साथ संकलित करने के लिए उन्हें उत्पन्न करने के लिए है) आप first देखेंगे आम (*COM*) अनुभाग में रखा:

[email protected]:~/C$ objdump -t file2.o 

a.o:  file format elf64-x86-64 

SYMBOL TABLE: 
0000000000000000 l df *ABS* 0000000000000000 file2.c 
0000000000000000 l d .text 0000000000000000 .text 
0000000000000000 l d .data 0000000000000000 .data 
0000000000000000 l d .bss 0000000000000000 .bss 
0000000000000000 l d .rodata 0000000000000000 .rodata 
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 
0000000000000000 l d .comment 0000000000000000 .comment 
0000000000000004  O *COM* 0000000000000004 first 
0000000000000000 g  F .text 0000000000000039 main 
0000000000000000   *UND* 0000000000000000 f 
0000000000000000   *UND* 0000000000000000 printf 
9

यह केवल संकलित करता है क्योंकि first केवल घोषित किया गया है, वास्तव में स्मृति में दो स्थान नहीं हैं बल्कि केवल एक ही हैं। बस पहले को int first=4; और int first=5; के साथ प्रारंभ करें और आपका लिंकर आपको त्रुटि दिखाएगा, उदा। जीसीसी:

b.o:b.c:(.data+0x0): multiple definition of `_first' 
a.o:a.c:(.data+0x0): first defined here 
collect2.exe: error: ld returned 1 exit status 
+0

अच्छा उत्तर, ++ – SomeWittyUsername

+0

नहीं, यह गलत है। सी मानक का कहना है कि इसे संकलित नहीं करना चाहिए, जीसीसी (लिंकर के साथ) में एक अनुकूलन है जो इसे तब तक काम करता है जब तक आप कोई मान निर्दिष्ट नहीं करते हैं। –

+0

@ क्रिसजफरसन आप कह रहे हैं कि मैं क्या कह रहा था –

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