从我的书中:
的.bss:
未初始化的全局C变量
COMMON:
尚未分配的未经初始化的数据对象
我不得不说,我看不出明显的区别。我甚至不太明白什么是无限制的,未分配的数据对象......似乎什么都没有。我使用GNU的readelf
工具试着看一些简单的C代码,但是找不到一个COMMON符号。我读过FORTRAN的COMMON类型是一个COMMON符号的例子 - 但我不知道FORTRAN
有人可以为我区分这两个吗?如果可能的话,希望用C的例子?非常感谢。
修改:来自this帖子,变量c在这里:
int c;
int main() {} ...
应该是COMMON。但是使用objdump -t
表明c在.bss ...
混淆
答案 0 :(得分:18)
// file a.c
// file-scope
int a = 0; // goes into BSS
将a.c
编译成目标文件a.o
后,a
符号进入BSS部分。
// file b.c
// file-scope
int b; // goes into COMMON section
将b.c
编译成目标文件b.o
后,b
符号进入COMMON部分。
关联a.o
和b.o
后,a
和b
符号都会进入BSS部分。公共符号仅存在于目标文件中,而不存在于可执行文件中。 Unix中COMMON符号的思想是允许在特定条件下在单个公共符号下对同一变量(在不同编译单元中)进行多个外部定义。
答案 1 :(得分:13)
Commons仅出现在链接阶段之前。 Commons是后来进入bss或数据的内容,但由链接器决定它的去向。这允许您在不同的编译单元中定义相同的变量。据我所知,这主要是为了允许一些古代头文件中包含int foo;
而不是extern int foo;
。
以下是它的工作原理:
$ cat > a.c
int foo;
$ cat > b.c
int foo;
$ cat > main.c
extern int foo;
int main(int argc, char **argv) { return foo; }
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ objdump -t a.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t b.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t x | grep foo
0000000000600828 g O .bss 0000000000000004 foo
$
请注意,这仅在初始化不同编译单元中的至多一个变量时才有效。
$ echo "int foo = 0;" > a.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ echo "int foo = 0;" > b.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
b.o:(.bss+0x0): multiple definition of `foo'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$
这是可怕的东西,与古代系统的兼容性,你永远不应该依赖它。做得恰当 - 在所有编译单元中只有一个全局变量定义,通过标题将其声明为extern。
答案 2 :(得分:8)
如果在链接期间允许common
,则不同的单位可以声明相同的变量,链接器会将它们定位在同一位置。类型甚至不需要相同,因此它是某种链接时间联合。这是Fortran的COMMON
功能。如果您在链接C时不允许common
,则这种情况将导致链接时间错误。这种common
链接只能用于未初始化的全局变量,因为否则不清楚应该采用哪种初始化。
转到bss
的全局变量只是未初始化的全局变量,C定义为初始化为0.大多数对象格式支持只给出大小的部分,加载器将用零填充整个部分。
PS:如果您使用gcc
,则可以使用-fno-common
选项强制common
符号到bss
部分,而Art认为这是一个很好且可取的做法。
答案 3 :(得分:-1)
静态变量最终出现在.bss部分。未初始化的全局变量(非静态)进入.common部分。
static a; //bss
int c; //.common
main(){
}