What happens when I print an uninitialized variable in C++?
为什么会打印 32767 (或其他随机数)?什么是 std::cout 打印?为什么不是NULL(或0)?
1 2 3 4 5
| int main()
{
int a;
std::cout << a;
} |
- 为什么它不是 NULL(或 0)?因为标准没有说它必须初始化为 0。
-
为什么人们只是喜欢看着枪管并扣动扳机并问"为什么我把头炸掉了?我拿起枪时不应该卸下Bullets吗"?
-
您对术语"未实例化引用"的使用不正确。 int a 不是参考变量,它是一个普通的旧值变量。尽管我从未真正听过任何人谈论"实例化"原始类型(人们通常只在谈论用户定义的类时使用"实例化"这个词,即 class 或 struct 类型),当您定义一个值变量(这就是您对 int a 所做的)时,它肯定会被实例化。
-
@user3528438,来自 Java,它甚至不允许指针(尽管数组有点接近),这有点不同
-
@JosephNields,Java 中的引用与 C 中的指针非常相似。
-
@user3528438 在 Java 中,您只有用户定义类型的指针,除非他们称它们为"引用"。
-
有趣的是,尽管我很确定之前有人问过这个问题,但我还没有找到 C 的问题。最Q
-
这是未定义的行为。您正在打印占用 a 内存的任何内容,在这种情况下恰好是 32767.
434511
这是因为具有自动存储持续时间的变量在 C 中不会自动初始化为零。在 C 中,您不需要为不需要的东西付费,并且自动初始化变量需要时间(将内存位置设置为零最终会减少为机器指令,然后将其转换为控制物理位)。
该变量被保留一个内存位置,并且碰巧在该内存位置有一些垃圾。 cout.
正在打印该垃圾
正如@dwcanillas 所指出的,这是未定义的行为。相关:C 中声明的、未初始化的变量会发生什么?它有价值吗?
来自 C 标准(强调我的):
8.5 初始化器 [dcl.init]
7) To default-initialize an object of type T means:
-
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
-
If T is an array type, each element is default-initialized.
-
Otherwise, no initialization is performed.
12) 如果没有为对象指定初始化器,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,如果没有对该对象执行初始化,则该对象将保留一个不确定的值,直到该值被替换(5.18)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。 — 尾注 ] 如果评估产生不确定的值,则行为未定义,但以下情况除外:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
434511
C 14 (N3936) [dcl.init]/12 涵盖了该行为:
If no initializer is specified for an object, the object is default-initialized. 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:
并且您的代码未包含在任何"以下情况"中,这些情况涵盖了允许传播 unsigned char 不确定值的几种情况。
434511
因为 "a" 不是全局/静态的。它是一个自动变量,在运行时进行初始化。如果它是全局的,则初始化为零将在编译时发生。即
?静态变量在编译时初始化,因为它们的地址是已知且固定的。将它们初始化为 0 不会产生运行时成本。
?自动变量对于不同的调用可以有不同的地址,并且每次调用函数时都必须在运行时进行初始化,从而产生可能不需要的运行时成本。如果您确实需要该初始化,请请求它。
-
这是未定义的行为。您正在打印占用 a 内存的任何内容,在这种情况下恰好是 32767.
434511
这是因为具有自动存储持续时间的变量在 C 中不会自动初始化为零。在 C 中,您不需要为不需要的东西付费,并且自动初始化变量需要时间(将内存位置设置为零最终会减少为机器指令,然后将其转换为控制物理位)。
该变量被保留一个内存位置,并且碰巧在该内存位置有一些垃圾。 cout.
正在打印该垃圾
正如@dwcanillas 所指出的,这是未定义的行为。相关:C 中声明的、未初始化的变量会发生什么?它有价值吗?
来自 C 标准(强调我的):
8.5 初始化器 [dcl.init]
7) To default-initialize an object of type T means:
-
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
-
If T is an array type, each element is default-initialized.
-
Otherwise, no initialization is performed.
12) 如果没有为对象指定初始化器,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,如果没有对该对象执行初始化,则该对象将保留一个不确定的值,直到该值被替换(5.18)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。 — 尾注 ] 如果评估产生不确定的值,则行为未定义,但以下情况除外:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
434511
C 14 (N3936) [dcl.init]/12 涵盖了该行为:
If no initializer is specified for an object, the object is default-initialized. 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:
并且您的代码未包含在任何"以下情况"中,这些情况涵盖了允许传播 unsigned char 不确定值的几种情况。
434511
因为 "a" 不是全局/静态的。它是一个自动变量,在运行时进行初始化。如果它是全局的,则初始化为零将在编译时发生。即
?静态变量在编译时初始化,因为它们的地址是已知且固定的。将它们初始化为 0 不会产生运行时成本。
?自动变量对于不同的调用可以有不同的地址,并且每次调用函数时都必须在运行时进行初始化,从而产生可能不需要的运行时成本。如果您确实需要该初始化,请请求它。
-
这是未定义的行为。您正在打印占用 a 内存的任何内容,在这种情况下恰好是 32767.
434511
这是因为具有自动存储持续时间的变量在 C 中不会自动初始化为零。在 C 中,您不需要为不需要的东西付费,并且自动初始化变量需要时间(将内存位置设置为零最终会减少为机器指令,然后将其转换为控制物理位)。
该变量被保留一个内存位置,并且碰巧在该内存位置有一些垃圾。 cout.
正在打印该垃圾
正如@dwcanillas 所指出的,这是未定义的行为。相关:C 中声明的、未初始化的变量会发生什么?它有价值吗?
来自 C 标准(强调我的):
8.5 初始化器 [dcl.init]
7) To default-initialize an object of type T means:
-
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
-
If T is an array type, each element is default-initialized.
-
Otherwise, no initialization is performed.
12) 如果没有为对象指定初始化器,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,如果没有对该对象执行初始化,则该对象将保留一个不确定的值,直到该值被替换(5.18)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。 — 尾注 ] 如果评估产生不确定的值,则行为未定义,但以下情况除外:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
434511
C 14 (N3936) [dcl.init]/12 涵盖了该行为:
If no initializer is specified for an object, the object is default-initialized. 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:
并且您的代码未包含在任何"以下情况"中,这些情况涵盖了允许传播 unsigned char 不确定值的几种情况。
434511
因为 "a" 不是全局/静态的。它是一个自动变量,在运行时进行初始化。如果它是全局的,则初始化为零将在编译时发生。即
?静态变量在编译时初始化,因为它们的地址是已知且固定的。将它们初始化为 0 不会产生运行时成本。
?自动变量对于不同的调用可以有不同的地址,并且每次调用函数时都必须在运行时进行初始化,从而产生可能不需要的运行时成本。如果您确实需要该初始化,请请求它。
这是因为具有自动存储持续时间的变量在 C 中不会自动初始化为零。在 C 中,您不需要为不需要的东西付费,并且自动初始化变量需要时间(将内存位置设置为零最终会减少为机器指令,然后将其转换为控制物理位)。
该变量被保留一个内存位置,并且碰巧在该内存位置有一些垃圾。 cout.
正在打印该垃圾
正如@dwcanillas 所指出的,这是未定义的行为。相关:C 中声明的、未初始化的变量会发生什么?它有价值吗?
来自 C 标准(强调我的):
8.5 初始化器 [dcl.init]
7) To default-initialize an object of type T means:
-
If T is a (possibly cv-qualified) class type (Clause 9), constructors are
considered. The applicable constructors are enumerated (13.3.1.3), and the best
one for the initializer () is chosen through overload resolution (13.3). The
constructor thus selected is called, with an empty argument list, to initialize >> the object.
-
If T is an array type, each element is default-initialized.
-
Otherwise, no initialization is performed.
12) 如果没有为对象指定初始化器,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,如果没有对该对象执行初始化,则该对象将保留一个不确定的值,直到该值被替换(5.18)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。 — 尾注 ] 如果评估产生不确定的值,则行为未定义,但以下情况除外:
— If an indeterminate value of unsigned narrow character type (3.9.1) is produced by the evaluation of:
— the second or third operand of a conditional expression (5.16),
— the right operand of a comma expression (5.19),
— the operand of a cast or conversion to an unsigned narrow character type (4.7, 5.2.3, 5.2.9, 5.4), or
— a discarded-value expression (Clause 5)
...
-
C 和 C 关于未初始化变量的规则有些不同。在 C 中,不确定的值可以在计算中传播。例如 int x; int y = x - 1; 在 C 中是合法的,并且导致 y 也是不确定的。但是,这会导致 C 中的 UB 。
-
@MattMcNabb 是的,我猜可能存在差异,正在热切地寻找骗子。但我最终找到了标准报价:)
这是未定义的行为。您正在打印占用 a 内存的任何内容,在这种情况下恰好是 32767.
- @vsoftco stackoverflow.com/questions/11962457/… 公平地说,这不是我认为它是 UB 的原因 :)
-
有趣...我会看一下帖子,谢谢!没错,就是UB,也相关stackoverflow.com/a/1597426/3093378, 1
-
你的回答自相矛盾。您首先(正确地)声明程序具有未定义的行为,然后您描述"它做了什么",就好像它已经定义了行为一样。
-
@AsteroidsWithWings 我不同意。我的观点(至少在这个答案的上下文中)是"未定义的行为"是"不可预测的行为"。我并不是暗示他的代码总是会输出 32767。那只是他使用的例子,他甚至说行为不一致。我只是在问题的上下文中指出未定义行为的结果。
-
没有"未定义行为的结果"。行为未定义。这就是它的意义所在。至少,对于在实践中可以合理预期的内容,这有点误导。
-
@AsteroidsWithWings 你错了。在这里,这篇文章比我能用 500 个字符更好地解释它:learncpp.com/cpp-tutorial/...
-
那篇文章正是我所说的。不,我没有错。
C 14 (N3936) [dcl.init]/12 涵盖了该行为:
If no initializer is specified for an object, the object is default-initialized. 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:
并且您的代码未包含在任何"以下情况"中,这些情况涵盖了允许传播 unsigned char 不确定值的几种情况。
因为 "a" 不是全局/静态的。它是一个自动变量,在运行时进行初始化。如果它是全局的,则初始化为零将在编译时发生。即
?静态变量在编译时初始化,因为它们的地址是已知且固定的。将它们初始化为 0 不会产生运行时成本。
?自动变量对于不同的调用可以有不同的地址,并且每次调用函数时都必须在运行时进行初始化,从而产生可能不需要的运行时成本。如果您确实需要该初始化,请请求它。