在 C 中,为啥我的初始化为 0 的 int 变量会被“nm”报告为未初始化?
Posted
技术标签:
【中文标题】在 C 中,为啥我的初始化为 0 的 int 变量会被“nm”报告为未初始化?【英文标题】:In C, why does my initialized to 0 int variable get reported as uninitialized by "nm"?在 C 中,为什么我的初始化为 0 的 int 变量会被“nm”报告为未初始化? 【发布时间】:2013-12-10 10:10:25 【问题描述】:我有以下 C 代码:
//declared at the beginning of the CAStar.c file:
int TERRAIN_PASSABLE = 1;
int TERRAIN_IMPASSABLE = 0;
int TERRAIN_SOME_WHAT_PASSABLE = 2;
我注意到,对于这些变量中的任何一个,如果它们具有非零值,它们会被 the "nm" command 报告为类型“D”(已初始化):
_TERRAIN_PASSABLE |00000008| D |
_TERRAIN_SOME_WHAT_PASSABLE|00000004| D |
但是,那些初始化为 0 的被报告为“B”(未初始化):
_TERRAIN_IMPASSABLE |00000000| B |
为什么“用 0 初始化”和“用除 0 以外的其他东西初始化”之间的区别?
【问题讨论】:
这可能是一种优化,编译器不会将堆变量初始化为零,因为它期望操作系统将内存清零……不过只是猜测。 @ypnos 好吧,老实说,我也有这样的想法。但是后来,我留下了其中一个真正未初始化的变量(只是:“int TERRAIN_SOME_WHAT_PASSABLE;”)。这次变量被报告为“C”,因此(再次)与使用 0 初始化时不同(也与使用非 0 初始化时不同)。 因为 ld.so 将所有内容初始化为零。与应用程序的运行时内存分配无关 (@ypnos) - 只是意味着运行时链接器不必将变量设置为任何特殊的值。 请澄清这些变量的声明位置,因为它很重要。目前,所有答案都只是猜测变量是在文件范围内声明的(“全局变量”)。 @Lundin 你说得对,我要更新代码 sn-p。对不起,谢谢。 【参考方案1】:这或多或少是关于 BSS 的工作原理和使用方式。 B 表示该变量将被放置在 BSS 部分(你是对的,它是未初始化的数据部分)。 D 表示符号放置在初始化的数据段中。
阅读例如 this 文章,了解更多关于 BSS 的工作原理和用途。
【讨论】:
我认为调用 BSS 未初始化是令人困惑的,因为它确实是零初始化的。许多编译器允许将数据放置到.no_init
部分或类似部分,这实际上是未初始化的。
谢谢,我现在明白了。它基本上是一个:“这里是所有具有默认值的变量”列表,它也不包含那些实际的默认值,以节省空间(对吗?)
@user694733 我也在想同样的事情,也许它应该被命名为更具表现力的东西,“未初始化”有点混乱。【参考方案2】:
这些变量很可能是在文件范围内声明的,并赋予它们静态存储持续时间。
出于优化目的,所有具有静态存储持续时间的变量都由编译器/链接器分为两类:初始化为 0 或初始化为其他值。初始化为零的变量放在通常称为.bss
的内存段中,而初始化为另一个值的变量放在.data
中。
这样做的原因是.bss
变量如果分配在相邻的内存中可以更快地初始化。基本上它们将使用单个memset
进行初始化。此外,它将减少所需的 ROM 数量。 Releated question with details.
编辑
.bss 变量最终处于未初始化状态的原因可能是因为 C 语言 (C11 6.7.9/10) 中有一条规则规定所有未由程序员显式初始化的静态存储持续时间变量(它们是“未初始化”),应初始化为零
【讨论】:
以上是关于在 C 中,为啥我的初始化为 0 的 int 变量会被“nm”报告为未初始化?的主要内容,如果未能解决你的问题,请参考以下文章