extern是可选的吗?

Chr*_*son 10 c linker compilation extern

我相信我会发疯,但请考虑以下C代码:

// file1.c
int first;

void f(void)
{ first = 2; }
Run Code Online (Sandbox Code Playgroud)
// file2.c
#include <stdio.h>

int first;
void f();
int main(void)
{
    first = 1;
    f();
    printf("%d", first);
}
Run Code Online (Sandbox Code Playgroud)

这两个文件,由于某种原因将编译和链接在一起,并打印2.我一直的印象是,除非我标记一个或另一个(但不是两者)的定义first有extern,这不会编译,这实际上整点extern!

Ber*_*ann 10

它只编译因为first只声明两次,实际上在内存中没有两个地方但只有一个.只需初始化一个int first=4;和另一个,int first=5;你的链接器将显示错误,例如GCC:

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
Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 6

在正常情况下(没有额外的gcc标志),您可以将此代码编译为:

gcc file1.c file2.c
Run Code Online (Sandbox Code Playgroud)

将要发生的是编译器将看到您有两个名为相同的全局变量,并且都没有初始化.然后它会将未初始化的全局变量放在代码的"公共"部分**.换句话说,它只有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
Run Code Online (Sandbox Code Playgroud)

要解决此问题,您需要添加extern除一个变量之外的所有变量.

警告:
现在假设您有两个不同大小的全局未初始化数组:

// file1.c
int first[10];

// file2.c
int first[20];
Run Code Online (Sandbox Code Playgroud)

好吧猜测是什么,编译它们不gcc -Wall file1.c file2.c产生任何警告或错误,即使它的大小不同,变量也很常见!

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

 //objdump from file2.c:
 0000000000000050       O *COM* 0000000000000020 first
Run Code Online (Sandbox Code Playgroud)

这是全局变量的危险之一.


**如果你看一下objdump*.o文件(你必须编译gcc -c生成它们),你会看到first放在common(*COM*)部分:

mike@mike-VirtualBox:~/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
Run Code Online (Sandbox Code Playgroud)