静态变量初始化?
我想知道为什么C、C++和Java中的静态变量默认初始化为零?为什么局部变量不是这样?
I want to know why exactly static variables in C, C++ and Java are initialized by zero by default? And why this is not true for local variables?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
C++标准第8.5.6段规定:
“Every object of static storage period Should be Zero-initialized at program Startup”
(标准还说局部变量的初始化是未定义的)
至于为什么,标准没有说;)一种猜测是它相当容易实现,没有任何额外的缺点。
Paragraph 8.5.6 of the C++ standard states that:
"Every object of static storage duration shall be zero-initialized at program startup"
(The standard also says that the initialization of local variables is undefined)
As to why, the standard doesn't say ;) One guess is that it's reasonably easy to implement without any additional downsides.
对于 java 来说:
局部变量必须先初始化,然后才能访问它,因为这是一个安全增益。编译器会检查变量是否已明确设置。
静态或类变量(具有 Object 类型)使用
null
进行初始化,因为编译器无法在编译时检查它们是否已初始化。如果程序访问未初始化的变量,不会让程序失败,而是使用null
隐式初始化该变量。具有本机类型的变量无法获取
null
值,因此非局部变量使用0
或false
进行初始化,作为后备。当然,这不是最好的解决方案,但我不知道更好的解决方案。 ;-)Speaking for java:
local variables must be initialized before you can access it, because it's a safety gain. The compiler checks for you, if the variable is definitly set.
static or class variables (with an Object type) are initialized with
null
, because the compiler can't check if they are initialized at compile time. Instead of letting the program fail if it accesses a non-initialized variable, it will be initialized implicit withnull
.Variables with a native type can't get a
null
value, so non-local variables are initialized with0
orfalse
, as a fallback. It's not best solution, sure, but I don't know a better one. ;-)所以在某种程度上,这些只是语言设计者的设计决策。但 Java 中做出这些决定的可能原因是:
对于局部变量,也可以想象,可以声明局部变量(在字节码/机器代码级别本质上意味着分配堆栈空间/移动堆栈指针),但实际上从未在特定代码路径中写入/读取。因此,没有默认值可以避免在这些情况下进行不必要的设置默认值的工作。
不过,我再说一遍,这些在某种程度上是设计决策。它们本质上是方便 JVM 实现和方便程序员之间的权衡。
注意:在 C/C++ 中,“静态”变量的含义与 Java 中的静态变量不同!
So to some extent these are just design decisions on the part of the language designers. But the probable reasons for these decisions in Java are:
In the case of local variables, it's also conceivable that a local variable could be declared (which at the bytecode/machine code level essentially means allocating stack space/moving the stack pointer) but then never actually written/read in a particular code path. So not having a default avoids doing unnecessary work of setting a default in those cases.
I repeat, though, these are design decisions to some extent. They're essentially a tradeoff between what's likely to be convenient for JVM implementations and convenient for programmers.
N.B. In C/C++, "static" variables mean a different thing to static variables in Java!
这只是一个猜测,但这可能是静态的方式,因为它很容易实现并且很有用。
编译器可以将所有变量共同分配到一个连续的内存区域,然后在
main()
执行之前发出代码(单个memset()
调用)来清除它叫。在许多情况下,它还可以依赖于操作系统可执行文件格式的功能,如果该格式支持“bss部分”,而是由加载器清除。这可以节省可执行文件的空间,并且可执行文件不会增加一兆字节。
对于局部变量,这些都不适用;它们是“动态”分配的(通常在堆栈上),清除它们会浪费资源,因为无论如何它们通常很快就会被分配。
This is just a guess, but it might be the way it is for statics since it's easy to implement, and useful.
The compiler can co-allocate all the variables into one contigous memory area, and then either emit code (a single
memset()
call) to clear it beforemain()
is called. In many cases it can also rely on features of the operating system's executable file format, if that format supports "bss sections", which are cleared by the loader instead. This saves space in the executable, you could haveand the executable would not grow by a megabyte.
For local variables, none of these apply; they are allocated "on the fly" (typically on a stack) and it would be a waste of resources to clear them, since they're typically going to be assigned to very soon anyway.
我对java一无所知,我怀疑java中的静态/局部变量是否有所不同。
至于c和c++,则是程序员关心代码效果、热爱掌控。初始化局部变量意味着每次程序进入作用域时都会执行额外的代码。对于频繁调用的函数来说这可能是一场灾难。
I have no idea about java and I doubt it's different for statics/locals in java.
As for c and c++, it's about programmers caring about their code effect and loving being in control. Initializing local variables would imply execution of extra code each time program enters the scope. For frequently called functions that may be a disaster.
这与C/C++中“只为你使用的东西付费”的概念有关。
对于静态变量,无需生成代码即可进行初始化。目标文件包含数据段中变量的初始值,当操作系统加载可执行文件时,它会在程序开始执行之前加载并映射该数据段。
对于局部变量,没有代码就无法初始化它们,因为它们不会被初始化一次,它们应该在每次进入它们的作用域时被初始化;它们也被分配在堆栈中,并且当分配发生时,一般情况下堆栈中的初始值就是之前的值(除了那些罕见的时刻,堆栈的增长量超过了之前的增长量)。
因此,要隐式初始化局部变量,编译器需要生成代码,而无需程序员显式命令它这样做,这完全违背了这一“哲学”。
关于Java,据我所知,变量总是在程序进入其作用域时初始化,无论它们是否是静态的。它们之间唯一的显着区别是静态变量的范围是整个程序。鉴于此,他们所有人的行为都是一致的。
This has to do with the concept of "only pay for what you use" in C/C++.
For static variables, an initialization can be made without generating code. The object file contains the initial values for the variables in the data segment and when the OS loads the executable it loads and maps this data segment before the program starts executing.
For local variables there's no way to initialize them without code because they are not initialized once, they should be initialized every time you enter their scope; also they are allocated in the stack, and when the allocation occurs the initial value in the stack in the general case is simply what was there before (except those rare moments you grow the stack more than it has grown before).
So to implicitly initialize a local variable the compiler would need to generate code without the programmer explicitly commanding it to do so, which is quite against that "philosophy".
About Java, as far as I know, variables are always initialized when the program enters their scope, no matter if they are static or not. The only significant difference between them is that the scope of static variables is the entire program. Given that, the behavior is consistent among all of them.
为什么静态变量被确定性地初始化而局部变量却没有?
看看静态变量是如何实现的。 它们的内存是在链接时分配的,并且它们的初始值也在链接时提供。没有运行时开销。
另一方面,局部变量的内存是在运行时分配的。堆栈必须增长。你不知道之前有什么。如果需要,您可以清除该内存(将其清零),但这会产生运行时开销。 C++ 哲学是“不用为不使用的东西付费”,因此默认情况下它不会将内存清零。
好的,但是为什么静态变量会初始化为零,而不是其他值?
嗯,您通常想对该变量执行某些操作。但是你怎么知道它是否已经初始化了呢?您可以创建一个静态布尔变量。但它还必须可靠地初始化为某些内容(最好是 false)。 指针怎么样?您宁愿将其初始化为 NULL,也不愿将其初始化为一些随机垃圾。 结构/记录怎么样?它里面还有一些其他的数据成员。将它们全部初始化为默认值是有意义的。但为了简单起见,如果您使用“初始化为 0”策略,则不必检查各个成员并检查它们的类型。 您可以将整个内存区域初始化为 0。
这并不是真正的技术要求。如果默认值不是 0,但初始化的语义仍然可以被认为是合理的,但仍然是确定性的。但是,这个值应该是多少呢?您可以很容易地解释为什么使用 0(尽管确实听起来有点武断),但解释 -1 或 1024 似乎更难(特别是变量可能不够大,无法容纳该值等)。
并且您始终可以显式初始化变量。
而且你总是有 C++ 标准的第 8.5.6 段,它说“静态存储持续时间的每个对象都应在程序启动时进行零初始化”。
有关详细信息,请参阅以下其他问题:
Why the static variables are deterministically initialized and local variables aren't?
See how the static variables are implemented. The memory for them is allocated at link time, and the initial value for them is also provided at link time. There is no runtime overhead.
On the other hand, the memory for local variables is allocated at run time. The stack has to grow. You don't know what was there before. If you want, you can clear that memory (zero it), but that would incur a runtime overhead. The C++ philosophy is "you don't pay for things you don't use", so it doesn't zero that memory by default.
OK, but why are static variables initialized to zero, and not some other value?
Well, you generally want to do something with that variable. But then how do you know if it has been initialized? You could create a static boolean variable. But then it also has to be reliably initialized to something (preferably false). How about a pointer? You'd rather want it initialized to NULL than some random garbage. How about a struct/record? It has some other data members inside. It makes sense to initialize all of them to their default values. But for simplicity, if you use the "initialize to 0" strategy, you don't have to inspect the individual members and check their types. You can just initialize the entire memory area to 0.
This is not really a technical requirement. The semantics of initialization could still be considered sane if the default value is something other than 0, but still deterministic. But then, what should that value be? You can quite easily explain why 0 is used (although indeed it sounds slightly arbitrary), but explaining -1 or 1024 seems to be even harder (especially that the variable may not be large enough to hold that value, etc).
And you can always initialize the variable explicitly.
And you always have paragraph 8.5.6 of the C++ standard which says "Every object of static storage duration shall be zero-initialized at program startup".
For more info, please refer to these other questions: