印象中以前學過C語言中跨檔案的全域變數是這樣宣告的。 檔案一:int g_var1;
檔案二:extern int g_val1;
然而,我從來沒有想過如果沒有extern的情況會發生什麼狀況。加上之前看過的objdump和nm後手癢,所以把可能的排列組合看看可能發生什麼事。
這邊要先知道common object表示object檔案已經紀錄下這個symbol,最後link的時候才會決定要怎麼處理。會放在common section 出處。
由於結果和分析又臭又長,連我自己都不太想回去看。建議先看結論,有疑惑再回來看結果和分析吧。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.1 LTS
Release: 14.04
Codename: trusty
非常簡單,就是有兩個檔案存放全域變數,每次測試時先更改全域變數
extern
全部的排列組合放在這邊int g_var1;
int g_var1;
#include <stdio.h>
extern int g_var1;
int main()
{
printf("Hello %d\n", g_var1);
return 0;
}
TARGET=glvar
SRCS=var_1.c var_2.c main.c
OBJS=$(patsubst %.c, %.o, $(SRCS))
CFLAGS=-g
$(TARGET): $(OBJS)
$(CC) -o $@ $^
test: $(TARGET)
objdump -t $(OBJS) $(TARGET)
nm -A $(OBJS) $(TARGET)
./$(TARGET)
clean:
rm -f $(TARGET) $(OBJS)
var1.c 宣告方式 | var2.c宣告方式 | 編譯結果 | nm 和 objdump 分析 |
---|---|---|---|
int g_var; | int g_var; | 成功 | 分析 |
int g_var = 2; | int g_var; | 成功 | 分析 |
int g_var; | int g_var = 3; | 成功 | 分析 |
int g_var = 2; | int g_var = 3; | 失敗 | 分析 |
var1.c 宣告方式 | var2.c宣告方式 | 編譯結果 | nm 和 objdump 分析 |
---|---|---|---|
int g_var; | extern int g_var; |
成功 | 分析 |
int g_var = 2; | extern int g_var; |
成功 | 分析 |
int g_var; | extern int g_var = 3; |
有警告 | 分析 |
int g_var = 2; | extern int g_var = 3; |
失敗 | 分析 |
var1.c 宣告方式 | var2.c宣告方式 | 編譯結果 | nm 和 objdump 分析 |
---|---|---|---|
extern int g_var; |
extern int g_var; |
link失敗 | 分析 |
extern int g_var = 2; |
extern int g_var; |
有警告 | 分析 |
extern int g_var |
extern int g_var = 3; |
有警告 | 分析 |
extern int g_var = 2; |
extern int g_var = 3; |
link失敗 | 分析 |
objdump -t
顯示object檔案的symbol table欄位資料:
.bss
,也就是未初始化的全域變數nm -A
顯示object檔案的symbol:
glvar:0000000000601044 B g_var1
.bss
,也就是未初始化的全域變數objdump -t
顯示object檔案的symbol table欄位資料:
.data
section.data
sectionnm -A
顯示object檔案的symbol:
和上面的差別只有var1.o和var2.o的結果對調而已。
$ make test
cc -g -c -o var_1.o var_1.c
cc -g -c -o var_2.o var_2.c
cc -g -c -o main.o main.c
cc -o glvar var_1.o var_2.o main.o
var_2.o:(.data+0x0): multiple definition of `g_var1'
var_1.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [glvar] Error 1
objdump -t
顯示object檔案的symbol table欄位資料:
.data
section.data
sectionnm -A
顯示object檔案的symbol:
objdump -t
顯示object檔案的symbol table欄位資料:
.data
sectionnm -A
顯示object檔案的symbol:
objdump -t
顯示object檔案的symbol table欄位資料:
.data
section.data
sectionnm -A
顯示object檔案的symbol:
$ make test
rm -f glvar var_1.o var_2.o main.o
cc -g -c -o var_1.o var_1.c
cc -g -c -o var_2.o var_2.c
var_2.c:1:12: warning: ‘g_var1’ initialized and declared ‘extern’ [enabled by default]
extern int g_var1 = 3;
^
cc -g -c -o main.o main.c
cc -o glvar var_1.o var_2.o main.o
var_2.o:(.data+0x0): multiple definition of `g_var1'
var_1.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [glvar] Error 1
objdump -t
顯示object檔案的symbol table欄位資料:
.data
sectio.data
sectionnm -A
顯示object檔案的symbol:
$ make test
cc -g -c -o var_1.o var_1.c
cc -g -c -o var_2.o var_2.c
var_2.c:1:12: warning: ‘g_var1’ initialized and declared ‘extern’ [enabled by default]
extern int g_var1 = 3;
^
cc -g -c -o main.o main.c
cc -o glvar var_1.o var_2.o main.o
var_2.o:(.data+0x0): multiple definition of `g_var1'
var_1.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [glvar] Error 1
objdump -t
顯示object檔案的symbol table欄位資料:
.data
section.data
sectionnm -A
顯示object檔案的symbol:
$ make test
cc -g -c -o var_1.o var_1.c
cc -g -c -o var_2.o var_2.c
cc -g -c -o main.o main.c
cc -o glvar var_1.o var_2.o main.o
main.o: In function `main':
/home/wen/work/practice/Linux_Programming_Practice/16_global_var/main.c:5: undefined reference to `g_var1'
collect2: error: ld returned 1 exit status
make: *** [glvar] Error 1
objdump -t
顯示object檔案的symbol table欄位資料:
nm -A
顯示object檔案的symbol:
var_1.c:1:12: warning: ‘g_var1’ initialized and declared ‘extern’ [enabled by default]
objdump -t
顯示object檔案的symbol table欄位資料:
.data
sectionnm -A
顯示object檔案的symbol:
和上面的差別只有var1.o和var2.o的結果對調而已。
$ make clean ; make test
rm -f glvar var_1.o var_2.o main.o
cc -g -c -o var_1.o var_1.c
var_1.c:1:12: warning: ‘g_var1’ initialized and declared ‘extern’ [enabled by default]
extern int g_var1 = 2;
^
cc -g -c -o var_2.o var_2.c
var_2.c:1:12: warning: ‘g_var1’ initialized and declared ‘extern’ [enabled by default]
extern int g_var1 = 3;
^
cc -g -c -o main.o main.c
cc -o glvar var_1.o var_2.o main.o
var_2.o:(.data+0x0): multiple definition of `g_var1'
var_1.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [glvar] Error 1
objdump -t
顯示object檔案的symbol table欄位資料:
.data
section.data
sectionnm -A
顯示object檔案的symbol:
gcc -c
產生的object檔案中未初始化的全域變數會放在common section而不是.bss
section,原因是link時期其他的object可能有相同名稱的symbol,而這些相同的symbol可能有初始化也可能沒有。而linker需要全盤瞭解後再做出決定要放在.bss
還是.data
section。.bss
section。.data
.data
sectionextern
全域變數的時候