【问题标题】:Initialization of int and double variables [duplicate]int和double变量的初始化[重复]
【发布时间】:2017-08-13 04:26:46
【问题描述】:

我有以下 C++ 代码:

#include <iostream>
using namespace std;
#include <stdio.h>


int main (int argc , char ** argv) 
{
    int i1;
    int i2;
    double d1;
    double d2;
    printf("i1: %d, i2: %d, d1: %f, d2: %f \n", i1, i2, d1, d2);
}

输出是

i1:4195872,i2:0,d1:0.000000,d2:0.000000

每次我运行程序时,我都会得到相同的输出。现在假设我正在使用以下代码:

#include <iostream>
using namespace std;
#include <stdio.h>


int main (int argc , char ** argv) 
{
    int i1;
    int i2;
    double d1;
    double d2;
    cout << "i1: " << i1;
    cout << " i2: " << i2;
    cout << " d1: " << d1;
    cout << " d2: " << d2;
}

现在我得到以下输出:

i1: 4196144 i2: 0 d1: 6.95294e-310 d2: 0

当我重新运行程序时,d1 的值略有变化,其他值保持不变。

为什么以这种方式初始化值?为什么没有随机初始化或者初始化为零?

【问题讨论】:

  • 这是未定义的行为。你不能指望变量有任何价值。

标签: c++ initialization


【解决方案1】:

为什么以这种方式初始化值?

基本类型和自动存储持续时间的默认初始化变量具有不确定的值。

为什么没有随机初始化或初始化为零?

因为标准没有这样说,而编译器实现者选择不这样做。随机化和零初始化都可能比不做都慢,所以选择似乎是合乎逻辑的。

标准所说的是读取不确定值具有未定义的行为(除了少数选择情况,请参阅标准引用)。

当前标准草案:

[dcl.init] (12) 如果没有为对象指定初始化器,则该对象被默认初始化。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有一个不确定的值,如果没有对该对象执行初始化,该对象将保留一个不确定的值,直到该值被替换([expr.ass])。 [ 注意:具有静态或线程存储持续时间的对象是零初始化的,请参阅[basic.start.static]。 — 尾注 ] 如果评估产生不确定的值,则行为未定义,但以下情况除外:

  • (12.1) 如果无符号窄字符类型或 std​::​byte 类型 ([cstddef.syn]) 的不确定值通过以下评估产生:

    • (12.1.1) 条件表达式的第二个或第三个操作数,
    • (12.1.2) 逗号表达式的右操作数,
    • (12.1.3) 强制转换或转换([conv.integral]、[expr.type.conv]、[expr.static.cast]、[expr.cast])到无符号窄字符类型的操作数或 std​::​byte 类型([cstddef.syn]),或
    • (12.1.4) 丢弃值表达式,

    那么运算的结果就是一个不确定的值。

  • (12.2) 如果一个不确定的无符号窄字符类型或 std​::​byte 类型的值是由一个简单赋值运算符的右操作数的评估产生的,该运算符的第一个操作数是一个无符号窄字符类型或 std 的左值​::​byte 类型,一个不确定的值替换左操作数所引用的对象的值。
  • (12.3) 如果在初始化无符号窄字符类型的对象时,初始化表达式的评估产生了无符号窄字符类型的不确定值,则该对象被初始化为不确定值。
  • (12.4) 如果在初始化 std​::​byte 类型的对象时通过初始化表达式的评估产生无符号窄字符类型或 std​::​byte 类型的不确定值,则该对象被初始化为一个不确定的值。

【讨论】:

  • 一定是unsigned char,对吧?并且仅在非常有限的情况下。
  • "(除非类型是窄字符)。" - 有趣。我才知道这个!请帮助我了解标准的相关部分......另外,我知道here解释的一般情况的一些基本原理,但是现在,我很好奇为什么unsigned char的例外情况@
  • @WhiZTiM 标准引用。 Angew 的修正是准确的。原因可能是与 C 的兼容性。我无法想象您会对不确定值有任何用途的情况。
  • 因此,未初始化的变量在打印其输出时具有未定义的行为。但是为什么我运行程序 1000 次输出是一样的呢?
  • @machinery 您是否期望它不一样?你为什么会这么期待?行为未定义。
【解决方案2】:

你的程序有未定义的行为,这意味着你得到的输出是完全随机的(事实上你得到了输出)。

在 C++ 中,非类类型的局部变量不会自动初始化。读取未初始化变量的值是未定义的。

【讨论】:

  • 好的,但是如果我运行程序 1000 次,我总是得到相同的输出...这不是随机的...为什么会这样?
  • @machinery 它可能恰好与您当前的操作系统版本、编译器版本、标准库版本、编译标志和月相一致。如果您更改其中任何一个,它可能会开始给出不同的结果。 未定义的行为是未定义的,任何事情都不能依赖它。
【解决方案3】:

这是未定义的行为,因为未初始化的变量持有垃圾值。

如果你不初始化函数内部定义的变量, 变量值保持未定义。这意味着元素承担 以前驻留在内存中该位置的任何值。

请参考cppreference

【讨论】:

  • 标准在哪里这么说的?对我来说听起来不太像标准话。
  • 但是为什么我运行程序 1000 次总是得到相同的输出?
猜你喜欢
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2015-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多