C 为什么在BSS和数据段中将不同大小的内存分配给integer?

C 为什么在BSS和数据段中将不同大小的内存分配给integer?,c,unix,memory,memory-management,C,Unix,Memory,Memory Management,请完成以下程序- #include <stdio.h> void main() { } 声明全局变量后- #include <stdio.h> int i; void main() { } 声明全局变量并用10初始化后- #include <stdio.h> int i=10; void main() { } 我的问题是,为什么全局变量“i”在存储在BSS时的内存大小为8字节,而在存储在数据段时的内存大小为4字节? 为什么在BSS和数据段中为整数

请完成以下程序-

#include <stdio.h>  
void main()
{
}
声明全局变量后-

#include <stdio.h>
int i;

void main()
{
}
声明全局变量并用10初始化后-

#include <stdio.h>
int i=10;

void main()
{
}
我的问题是,为什么全局变量“i”在存储在BSS时的内存大小为8字节,而在存储在数据段时的内存大小为4字节? 为什么在BSS和数据段中为整数分配内存会有差异

为什么全局变量“i”存储在BSS中时内存大小为8字节,而存储在数据段中时内存大小为4字节

首先,为什么数据段中有4个字节?

正如许多人已经回答过的那样,.data段包含任何预先初始化的全局或静态变量。一个整数的大小为4字节,当全局
inti=10时,它反映在数据段大小中在您的程序中

现在,为什么.bss段中有8个字节?

您之所以观察到这种行为,是因为GNU linkerGNU ld默认链接器脚本。您可以获取有关链接器脚本的信息

链接时,GNU linker()使用默认的链接器脚本

默认链接器脚本指定.bss段的对齐方式

如果要查看默认链接器脚本,可以使用命令-

gcc -Wl,-verbose main.c
gcc
命令的输出将包含以下语句:

using internal linker script:
==================================================
// The content between these two lines is the default linker script
==================================================
在默认链接器脚本中,您可以找到
.bss
部分:

  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 64 / 8 : 1);
  }
在这里,您可以看到
=对齐(.!=0?64/8:1)表示默认对齐方式为8字节

该方案:

#include <stdio.h>
int i;

void main()
{
}
[bss=24字节(16+8)]

GNU链接器提供了一个将自己的链接器脚本传递给它的设置,在这种情况下,它使用传递给它的脚本来构建目标,而不是默认的链接器脚本

要尝试此操作,可以将默认链接器脚本的内容复制到文件中,并使用此命令将链接器脚本传递到
GNU ld

gcc -Xlinker -T my_linker_script main.c
因为您可以拥有自己的链接器脚本,所以您可以对其进行更改并查看行为的更改

.bss
部分中,更改此
=对齐(.!=0?64/8:1)
=对齐(.!=0?32/8:1)。这会将默认对齐方式从8字节更改为4字节。现在使用带有此更改的链接器脚本构建您的目标

输出为:

# size a.out
   text    data     bss     dec     hex filename
   1040     484      20    1544     608 a.out
在这里您可以看到,由于4字节对齐,bss的大小是
20
字节(16+4)


希望这能回答您的问题。

也许这是一个对齐要求。在我的机器(x86_64 Linux)上,.bss大小似乎是8的整数倍(向下),而.data部分则不是。现在,我需要添加两个未初始化的int以增加8,但是每个初始化的int会使.data部分增加4。有趣的问题。未初始化的变量位于
bss
部分,该部分应该是一个虚拟部分,它只包含一个要保留的空间计数器,但按照二进制格式的要求在边界上对齐。声明初始化变量时,它的init值存储在数据段中,使32位
int
的值增加4字节。这将最终改变文件图像中后面的
bss
部分上的位置。如果对齐间距被计为
bss
space,则该值将发生变化。由于所有这些都高度依赖于编译器,您应该说明您使用的编译器和版本以及编译器标志。@Frankie_C global和static默认初始化为0。绝对正确。。。
#include <stdio.h>
int i;

void main()
{
}
# size a.out
   text    data     bss     dec     hex filename
   1040     484      24    1548     60c a.out
gcc -Xlinker -T my_linker_script main.c
# size a.out
   text    data     bss     dec     hex filename
   1040     484      20    1544     608 a.out