C中的局部和静态变量

时间:2012-11-27 09:22:38

标签: c assembly static

编译时:

// external definitions
int value1 = 0;
static int value2 = 0;

gcc编译器生成以下程序集:

.globl value1
        .bss
        .align 4
        .type   value1, @object
        .size   value1, 4
value1:
        .zero   4
        .local  value2
        .comm   value2,4,4

但是,当我将变量初始化为非零值时,例如:

// external definitions
int value1 = 1;
static int value2 = 1;

gcc编译器生成了以下内容:

.globl value1
        .data
        .align 4
        .type   value1, @object
        .size   value1, 4
value1:
        .long   1
        .align 4
        .type   value2, @object
        .size   value2, 4
value2:
        .long   1

我的问题是:

  1. 为什么在第一种情况下,值在bss段中分配,而在第二种情况下在数据段中。
  2. 为什么value2变量在第一种情况下定义为.local和.comm,而在第二种情况下不定义。

3 个答案:

答案 0 :(得分:11)

一般来说,bss部分包含未初始化的值,data部分包含初始化值。但是,gcc将初始化为零的值放入bss部分而不是data部分,因为bss部分在运行时已归零,它没有多大意义要在data部分存储零,这可以节省一些磁盘空间,来自man gcc:

  

-fno-zero-initialized-in-bss如果目标支持BSS部分, GCC默认将初始化为零的变量放入BSS。这个   可以节省生成代码中的空间。此选项会关闭此选项   行为,因为一些程序明确依赖变量   数据部分

我不确定为什么.comm与对象文件本地的静态存储一起使用,它通常用于声明常见符号,如果不< / em>已定义/初始化,应该由链接器与其他目标文件中具有相同名称的符号合并,这就是为什么在第二个示例中没有使用它,因为变量是从as {{3}初始化的}}

  

.comm声明一个名为symbol的常用符号。链接时,很常见   一个目标文件中的符号可以与已定义或共同的内容合并   另一个目标文件中同名的符号

答案 1 :(得分:5)

第一种情况是因为您将值初始化为零。它是C standard(第6.7.8节)的一部分,如果没有指定,则全局整数初始化为0。因此,文件格式通过将特殊部分置于:bss中来提供更小的二进制文件。如果您查看一些ELF specification(第I-15页),您会发现:

  

.bss此部分包含有助于该程序的未初始化数据   记忆图像。根据定义,系统用零初始化数据   当程序开始运行时。该部分不占用任何文件空间   由部分类型SHT_NOBITS指示。

在第一种情况下,编译器进行了优化。它不需要在实际二进制文件中占用空间来存储初始化程序,因为它可以使用bss段并获得您想要的免费段。

现在,你有一个来自外部源的静态的事实有点有趣(通常不会这样做)。在编译的模块中,不应与其他模块共享,并应标记为.local。我怀疑它是这样做的,因为没有为初始化程序存储的实际值。

在第二个示例中,因为您已经给出了非零初始值设定项,所以它知道它位于初始化数据段data中。 value1看起来非常相似,但对于value2,编译器需要为初始化程序保留空间。在这种情况下,它不需要标记为.local,因为它可以放下值并完成它。它不是全局的,因为它没有.globl语句。

BTW,http://refspecs.linuxbase.org/是访问二进制格式等一些低级细节的好地方。

答案 2 :(得分:3)

BSS是包含在运行时初始化的数据的段,其中数据段包含在程序二进制文件中初始化的数据。

现在,无论是否在程序中明确地完成,静态变量总是被初始化。但是有两个单独的类别,初始化(DS)和未初始化(BSS)静态。

BSS中存在的所有值都是未在程序代码中初始化的值,因此在程序在运行时加载到0(如果是整数)时为初始化,对于指针等为null。

因此,当您使用0初始化时,该值将转到BSS,其中分配的任何其他值将在数据段中分配变量。

一个有趣的结果是,在BSS中初始化的数据大小将不包含在程序二进制文件中,其中包含数据段中的数据大小。

尝试分配大型静态数组并在程序中使用它。在代码中未明确初始化时,请查看可执行文件大小。然后用非零值(如

)初始化它
static int arr[1000] = {2};

后一种情况下可执行文件的大小会大得多