繁体   English   中英

C/C++ 中未初始化的变量会怎样?

[英]What happens to uninitialized variables in C/C++?

来自 Lippman 的“C++ Primer”,

当我们定义一个变量时,我们应该给它一个初始值,除非我们确定在变量被用于任何其他目的之前初始值将被覆盖。 如果我们不能保证变量在被读取之前会被重置,我们应该初始化它。

  1. 如果在某个操作中使用未初始化的变量会怎样? 它会崩溃/代码会编译失败吗?

    我在 inte.net 上搜索了相同的答案,但有不同的“声明”。 因此,以下问题,

  2. C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

  3. 关于类似的查询,我如何以及在哪里可以找到“官方”答案? 业余爱好者查一下C和C++标准实用吗?

如果在操作中使用未初始化的变量会发生什么?

这取决于。 如果操作使用变量的值,并且变量的类型和表达式不被排除在外,那么程序的行为是 undefined

如果不使用该值 - 例如在sizeof运算符的情况下,则不会发生任何特殊情况,而初始化变量不会发生这种情况。

C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

它们使用不同的措辞,但在这方面本质上非常相似。

C 通过“陷阱表示”的概念定义了不确定值的未定义行为,并指定了保证没有陷阱表示的类型。

C++ 没有定义“陷阱表示”的概念,而是列出了生成不确定值不会导致未定义行为的例外情况。 这些情况与 C 中的异常类型有一些重叠,但并不完全相同。

关于类似的查询,我如何以及在哪里可以找到“官方”答案?

官方答案——如果有的话——总是在语言标准文档中。

C++ 标准 [dcl.init] 第 12 段 [ISO/IEC 14882-2014] 规定如下:

如果没有为 object 指定初始化程序,则默认初始化 object。 When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. 如果评估产生不确定的值,则行为未定义,但以下情况除外:

(结束报价)

所以使用未初始化的变量会导致未定义的行为

未定义的行为意味着任何1都可能发生,包括但不限于给出您预期的 output 的程序。 永远不要依赖(或基于)具有未定义行为的程序的 output。 该程序可能会给出您预期的 output 或者它可能会崩溃。


1有关未定义行为的更技术上准确的定义,请参见此处提到:对程序的行为没有限制

Q.1) 如果在操作中使用未初始化的变量会发生什么? 它会崩溃/代码会无法编译吗?

许多编译器会警告您有关不正确使用未初始化变量值的代码。 许多编译器都有一个选项说“将警告视为错误”。 因此,根据您使用的编译器和调用它的选项标志,代码可能无法编译,尽管我们不能说它编译失败。

如果代码确实编译了,并且您尝试运行它,那么显然无法预测会发生什么。 在大多数情况下,变量将开始包含“不确定”值。 这个不确定的值是否会导致您的程序正常工作、工作不正确或崩溃,这是任何人的猜测。 如果变量是 integer 并且您尝试对其进行一些数学运算,您可能会得到一个奇怪的答案。 但是如果变量是一个指针并且你试图间接使用它,你很可能会崩溃。

人们常说未初始化的局部变量一开始就包含“随机垃圾”,但这可能会产生误导,正如在此处发布问题的人数所证明的那样,在他们尝试过的程序中,该值不是随机的, 但始终为 0 或始终相同。 所以我想说,未初始化的局部变量永远不会像你期望的那样开始。 如果您期望它们是随机的,您会发现(至少在任何一天)它们是可重复和可预测的。 但是,如果您希望它们是可预测的(并且,如果您编写依赖于它的代码,上帝会帮助您),那么通过 jingo,您会发现它们是非常随机的。

使用未初始化的变量是否会使您的程序正式未定义是一个复杂的问题。 但你不妨假设它确实如此,因为这是你想要避免的情况,就像你避免任何其他危险的、未定义的行为一样。

有关在这种情况下未定义和不确定行为之间的细微区别的更多(更多)信息,请参阅这个旧问题另一个旧问题

Q.2) C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

他们可能会有所不同。 正如我在上面提到的,至少在 C 中,事实证明并非所有未初始化的局部变量的使用都是正式未定义的。 (有些只是“不确定的”。)但是这里的其他答案从 C++ 标准中引用的段落听起来好像一直没有定义。 同样,出于实际目的,这个问题可能并不重要,因为正如我所说,无论如何你都想避免它。

Q.3) 关于类似的查询,我如何以及在哪里可以找到“官方”答案? 业余爱好者查 C 和 C++ 标准是否实用?

获得标准的副本并不总是那么容易(更不用说通常要花钱的官方标准了),而且标准可能难以阅读和正确解释,但是是的,只要付出努力,任何人都可以获得、阅读和尝试使用标准回答问题。 您可能并不总是第一次做出正确的解释(因此您可能需要寻求帮助),但我不会说这是不尝试的理由。 (一方面,任何人都可以阅读任何文档,但最终没有做出正确的解释;这种现象不仅限于业余程序员阅读复杂的语言标准文档!)

如果它是一个局部变量,那么它包含垃圾值(即,在分配变量的 memory 位置中已经存在的任何值,从先前的使用)。

如果它是 static 或全局变量,那么它们会自动初始化为“0”。

现在,如果您在计算中使用垃圾值,您将得到无意义的结果。

如果您尝试使用*运算符取消引用包含垃圾值的变量中的值并对其进行读取/写入,它可能会出现不可预知的行为(例如,垃圾值是一个数字,也是 memory 上分配的位置的地址到另一个进程,所以现在你正在尝试访问 memory ,你不允许访问并且你的程序会崩溃)。

标准说它是未定义的。

然而,在 Unix 或基于 VMS 的系统(Gnu/Linux、UNIX、BSD、MS-Windows > XP 或 NT、MacOS > X)上,堆栈和堆被初始化为零(这是出于安全原因。现在让你的代码工作。)

但是,如果您将 go 上下堆栈或释放然后 malloc 则数据将是随机垃圾。 (随机垃圾可能还有其他原因。不要依赖未定义的行为)。

程序会崩溃吗? (通过这个,你的意思是在运行时检测错误。)

可能不是,但这又是未定义的行为。 C 解释器可以执行此操作。

还要注意,一些 C++ 类型有一个构造函数,可以进行良好定义的初始化。

您已标记 C 和 C++。 在 C 中,未初始化的变量可能包含垃圾位。 通常你的编译器会放零位,但你不能指望它。 因此,如果您在没有显式初始化的情况下使用该变量,则结果可能是合理的,也可能不是。 严格来说,这是未定义的行为,所以任何事情都可能发生。

C++ 对简单变量具有相同的功能,但有一个有趣的例外:虽然int x[3]包含垃圾,但std::vector x(3)包含零。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM