"multiple definition of value"在 g++ 中编译具有未初始化全局但不是 gcc 的 C 程序时



我试图了解头文件中 extern 和全局变量声明的用法,所以我想出了以下用 C 编写的测试程序。

主.c 文件

//main.c
#include "global.h"
#include <stdio.h>
int nExternValue = 6;
int main(int argc, char* argv[])
{
    printf("%d n", nValue);
    printf("%d n", nExternValue);
    AddToValue();
    printf("%d n", nValue);
    printf("%d n", nExternValue);
}

全局.h 文件

#ifndef _GLOBAL_H
#define _GLOBAL_H
//WRONG! do not declare a variable here
int nValue;
//OK! extern variable makes it a global accessable variable
extern int nExternValue;
//OK! function prototype can be placed in h file
int AddToValue();
#endif

以及实现 AddToValue 函数的 AddValue.c 文件。

#include "global.h"
int AddToValue() {
    nValue++;
    nExternValue++;
}

我使用 gcc 编译了应用程序,并运行了它:

$ gcc main.c AddValue.c -o test
$./test
0 
6 
1 
7 

我使用 g++ 编译了该应用程序,并收到以下链接器错误:

$ g++ main.c AddValue.c -o test
/tmp/ccFyGDYM.o:(.bss+0x0): multiple definition of `nValue'
/tmp/cc3ixXdu.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

为什么 gcc 链接器不会产生错误?我虽然 nValue 变量会被声明多次,这会产生错误!

$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C和C++是不同的语言。例如,上述程序是有效的 C 程序,但C++程序格式不正确。您违反了C++的一个定义规则。C 中没有相应的规则。

使用 gcc 编译时,您将上述文本编译为 C 程序。使用 g++ 编译时,您将上述文本编译为C++程序。

当使用 gcc 编译时,未初始化的全局变量(如 nValue)将被视为公共符号。在不同编译单元中出现的相同公共符号将在链接期间合并。如果使用 g++ 编译(这意味着源程序将被视为C++程序),则未初始化的全局变量将隐式初始化为默认值 0。由于 global.h 包含在多个源文件中,编译器将考虑多次定义的符号 nValue。

也请看一下这篇文章:为什么未初始化的全局变量是弱符号?

最新更新