简体   繁体   English

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

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

From "C++ Primer" by Lippman,来自 Lippman 的“C++ Primer”,

When we define a variable, we should give it an initial value unless we are certain that the initial value will be overwritten before the variable is used for any other purpose.当我们定义一个变量时,我们应该给它一个初始值,除非我们确定在变量被用于任何其他目的之前初始值将被覆盖。 If we cannot guarantee that the variable will be reset before being read, we should initialize it.如果我们不能保证变量在被读取之前会被重置,我们应该初始化它。

  1. What happens if an uninitialized variable is used in say an operation?如果在某个操作中使用未初始化的变量会怎样? Will it crash/ will the code fail to compile?它会崩溃/代码会编译失败吗?

    I searched the inte.net for answer to the same but there were differing 'claims'.我在 inte.net 上搜索了相同的答案,但有不同的“声明”。 Hence the following questions,因此,以下问题,

  2. Will C and C++ standards differ in how they treat an uninitialized variable? C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

  3. Regarding similar queries, how and where can I find an 'official' answer?关于类似的查询,我如何以及在哪里可以找到“官方”答案? Is it practical for an amateur to look up the C and C++ standards?业余爱好者查一下C和C++标准实用吗?

What happens if an uninitialized variable is used in say an operation?如果在操作中使用未初始化的变量会发生什么?

It depends.这取决于。 If the operation uses the value of the variable, and the type of the variable and the expression aren't excepted from it, then the behaviour of the program is undefined .如果操作使用变量的值,并且变量的类型和表达式不被排除在外,那么程序的行为是 undefined

If the value isn't used - such as in the case of sizeof operator, then nothing particular happens that wouldn't happen with an initialised variable.如果不使用该值 - 例如在sizeof运算符的情况下,则不会发生任何特殊情况,而初始化变量不会发生这种情况。

Will C and C++ standards differ in how they treat an uninitialized variable? C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

They use different wording, but are essentially quite similar in this regard.它们使用不同的措辞,但在这方面本质上非常相似。

C defines the undefined behaviour of indeterminate values through the concept of "trap representation" and specifies types that are guaranteed to not have trap representations. C 通过“陷阱表示”的概念定义了不确定值的未定义行为,并指定了保证没有陷阱表示的类型。

C++ doesn't define the concept of "trap representation", but rather lists exceptional cases where producing an indeterminate value doesn't result in undefined behaviour. C++ 没有定义“陷阱表示”的概念,而是列出了生成不确定值不会导致未定义行为的例外情况。 These cases have some overlap with the exceptional types in C, but aren't exactly the same.这些情况与 C 中的异常类型有一些重叠,但并不完全相同。

Regarding similar queries, how and where can I find an 'official' answer?关于类似的查询,我如何以及在哪里可以找到“官方”答案?

The official answer - if there is one - is always in the language standard document.官方答案——如果有的话——总是在语言标准文档中。

The C++ Standard, [dcl.init], paragraph 12 [ISO/IEC 14882-2014], states the following: C++ 标准 [dcl.init] 第 12 段 [ISO/IEC 14882-2014] 规定如下:

If no initializer is specified for an object, the object is default-initialized.如果没有为 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. 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. If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:如果评估产生不确定的值,则行为未定义,但以下情况除外:

(end quote) (结束报价)

So using an uninitialized variable will result in undefined behavior .所以使用未初始化的变量会导致未定义的行为

Undefined behavior means anything 1 can happen including but not limited to the program giving your expected output.未定义的行为意味着任何1都可能发生,包括但不限于给出您预期的 output 的程序。 But never rely (or make conclusions based) on the output of a program that has undefined behavior.永远不要依赖(或基于)具有未定义行为的程序的 output。 The program may give your expected output or it may crash.该程序可能会给出您预期的 output 或者它可能会崩溃。


1 For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program . 1有关未定义行为的更技术上准确的定义,请参见此处提到:对程序的行为没有限制

Q.1) What happens if an uninitialized variable is used in say an operation? Q.1) 如果在操作中使用未初始化的变量会发生什么? Will it crash/ will the code fail to compile?它会崩溃/代码会无法编译吗?

Many compilers will warn you about code that improperly uses the value of an uninitialized variable.许多编译器会警告您有关不正确使用未初始化变量值的代码。 Many compilers have an option that says "treat warnings as errors".许多编译器都有一个选项说“将警告视为错误”。 So depending on the compiler you're using and the option flags you invoke it with, the code might fail to compile, although we can't say that it will fail to compile.因此,根据您使用的编译器和调用它的选项标志,代码可能无法编译,尽管我们不能说它编译失败。

If the code does compile, and you try to run it, it's obviously impossible to predict what will happen.如果代码确实编译了,并且您尝试运行它,那么显然无法预测会发生什么。 In most cases the variable will start out containing an "indeterminate" value.在大多数情况下,变量将开始包含“不确定”值。 Whether that indeterminate value will cause your program to work correctly, or work incorrectly, or crash, is anyone's guess.这个不确定的值是否会导致您的程序正常工作、工作不正确或崩溃,这是任何人的猜测。 If the variable is an integer and you try to do some math on it, you'll probably just get a weird answer.如果变量是 integer 并且您尝试对其进行一些数学运算,您可能会得到一个奇怪的答案。 But if the variable is a pointer and you try to indirect on it, you're quite likely to get a crash.但是如果变量是一个指针并且你试图间接使用它,你很可能会崩溃。

It's often said that uninitialized local variables start out containing "random garbage", but that can be misleading, as evidenced by the number of people who post questions here pointing out that, in their program where they tried it, the value wasn't random, but was always 0 or was always the same.人们常说未初始化的局部变量一开始就包含“随机垃圾”,但这可能会产生误导,正如在此处发布问题的人数所证明的那样,在他们尝试过的程序中,该值不是随机的, 但始终为 0 或始终相同。 So I like to say that uninitialized local variables never start out holding what you expect.所以我想说,未初始化的局部变量永远不会像你期望的那样开始。 If you expected them to be random, you'll find that (at least on any given day) they're repeatable and predictable.如果您期望它们是随机的,您会发现(至少在任何一天)它们是可重复和可预测的。 But if you expect them to be predictable (and, god help you, if you write code that depends on it), then by jingo, you'll find that they're quite random.但是,如果您希望它们是可预测的(并且,如果您编写依赖于它的代码,上帝会帮助您),那么通过 jingo,您会发现它们是非常随机的。

Whether use of an uninitialized variable makes your program formally undefined turns out to be a complicated question.使用未初始化的变量是否会使您的程序正式未定义是一个复杂的问题。 But you might as well assume that it does, because it's a case you want to avoid just as assiduously as you avoid any other dangerous, undefined behavior.但你不妨假设它确实如此,因为这是你想要避免的情况,就像你避免任何其他危险的、未定义的行为一样。

See this old question and this other old question for more (much more.) information on the fine distinctions between undefined and indeterminate behavior in this case.有关在这种情况下未定义和不确定行为之间的细微区别的更多(更多)信息,请参阅这个旧问题另一个旧问题

Q.2) Will C and C++ standards differ in how they treat an uninitialized variable? Q.2) C 和 C++ 标准在处理未初始化变量的方式上会有所不同吗?

They might differ.他们可能会有所不同。 As I alluded to above, and at least in C, it turns out that not all uses of uninitialized local variables are formally undefined.正如我在上面提到的,至少在 C 中,事实证明并非所有未初始化的局部变量的使用都是正式未定义的。 (Some are merely "indeterminate".) But the passages quoted from the C++ standards by other answers here make it sound like it's undefined there all the time. (有些只是“不确定的”。)但是这里的其他答案从 C++ 标准中引用的段落听起来好像一直没有定义。 Again, for practical purposes, the question probably doesn't matter, because as I said, you'll want to avoid it no matter what.同样,出于实际目的,这个问题可能并不重要,因为正如我所说,无论如何你都想避免它。

Q.3) Regarding similar queries, how and where can I find an 'official' answer? Q.3) 关于类似的查询,我如何以及在哪里可以找到“官方”答案? Is it practical for an amateur to look up the C and C++ standards?业余爱好者查 C 和 C++ 标准是否实用?

It is not always easy to obtain copies of the standards (let alone official ones, which often cost money), and the standards can be difficult to read and to properly interpret, but yes, given effort, anyone can obtain, read, and attempt to answer questions using the standards.获得标准的副本并不总是那么容易(更不用说通常要花钱的官方标准了),而且标准可能难以阅读和正确解释,但是是的,只要付出努力,任何人都可以获得、阅读和尝试使用标准回答问题。 You might not always make the correct interpretation the first time (and you may therefore need to ask for help), but I wouldn't say that's a reason not to try.您可能并不总是第一次做出正确的解释(因此您可能需要寻求帮助),但我不会说这是不尝试的理由。 (For one thing, anyone can read any document and end up not making the correct interpretation the first time; this phenomenon is not limited to amateur programmers reading complex language standards documents!) (一方面,任何人都可以阅读任何文档,但最终没有做出正确的解释;这种现象不仅限于业余程序员阅读复杂的语言标准文档!)

If it's a local variable, then it contains garbage values (ie whatever values were already present in the memory location where the variable got allotted, from prior use).如果它是一个局部变量,那么它包含垃圾值(即,在分配变量的 memory 位置中已经存在的任何值,从先前的使用)。

If it's a static or global variable, then they get initialized automatically with '0'.如果它是 static 或全局变量,那么它们会自动初始化为“0”。

Now if you use garbage values in a calculation, you'll get nonsensical results.现在,如果您在计算中使用垃圾值,您将得到无意义的结果。

If you try to dereference the value inside a variable containing garbage values with the * operator and read it/write to it, it can have unpredictable behavior (say the garbage value was a number that was also the address of a location on the memory allotted to a different process, so now you're trying access memory that you're not allowed to access and your program will crash).如果您尝试使用*运算符取消引用包含垃圾值的变量中的值并对其进行读取/写入,它可能会出现不可预知的行为(例如,垃圾值是一个数字,也是 memory 上分配的位置的地址到另一个进程,所以现在你正在尝试访问 memory ,你不允许访问并且你的程序会崩溃)。

The standard says it is undefined.标准说它是未定义的。

However on a Unix or VMS based system (Gnu/Linux, UNIX, BSD, MS-Windows > XP or NT, MacOS > X) then the stack and heap are initialised to zero (this is done for security reasons. Now to make your code work.)然而,在 Unix 或基于 VMS 的系统(Gnu/Linux、UNIX、BSD、MS-Windows > XP 或 NT、MacOS > X)上,堆栈和堆被初始化为零(这是出于安全原因。现在让你的代码工作。)

However if you go up and down the stack or free then malloc then the data will be random rubish.但是,如果您将 go 上下堆栈或释放然后 malloc 则数据将是随机垃圾。 (there may be other causes of random rubish. Don't rely on undefined behaviours). (随机垃圾可能还有其他原因。不要依赖未定义的行为)。

Could the program crash?程序会崩溃吗? (By this, you mean detect error at run-time.) (通过这个,你的意思是在运行时检测错误。)

Probably not, but again this is undefined behaviour.可能不是,但这又是未定义的行为。 A C interpreter may do this. C 解释器可以执行此操作。

Note also, some C++ types have a constructor that does well-defined initialisation.还要注意,一些 C++ 类型有一个构造函数,可以进行良好定义的初始化。

You have tagged both C and C++.您已标记 C 和 C++。 In C, an uninitialized variable probably has junk bits.在 C 中,未初始化的变量可能包含垃圾位。 Often your compiler with put zero bits there, but you can not count on it.通常你的编译器会放零位,但你不能指望它。 So if you use that variable without explicitly initializing, the result may be sensible and it may not.因此,如果您在没有显式初始化的情况下使用该变量,则结果可能是合理的,也可能不是。 And strictly speaking this is undefined behavior, so anything at all may happen.严格来说,这是未定义的行为,所以任何事情都可能发生。

C++ has the same for simple variables, but there is an interesting exception: while a int x[3] contains junk, std::vector x(3) contains zeros. C++ 对简单变量具有相同的功能,但有一个有趣的例外:虽然int x[3]包含垃圾,但std::vector x(3)包含零。

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

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