在C中,它是O.K.增加一个未初始化的int?

时间:2015-02-02 04:00:33

标签: c initialization

根据this SO answer,在C中递增未初始化的int会导致未定义的行为。但是,如果我完全不关心初始值,那该怎么办呢?例如,如果我只想要递增ID怎么办?这是危险的不良做法是出于任何原因吗?

3 个答案:

答案 0 :(得分:8)

如果访问具有自动存储持续时间的对象的值,并且该对象未初始化,则行为未定义。 N1570 6.3.2.1第2段(即ISO C标准的最新公开草案)明确并正式地阐述了这一点。

" 未定义的行为"并不仅仅意味着您可能获得任意值。它表示在使用不可移植或错误的程序结构或错误数据时的行为,本国际标准没有规定任何要求" (N1570 3.4.3)。语言标准几乎没有说明访问这样一个对象的价值意味着什么。它实际上是纯粹的胡言乱语。 (标准的笑话是,未定义的行为可能会导致恶魔飞出你的鼻子。当然,在现实生活中它不能 - 但如果确实如此,你就不会抱怨编译器不符合要求。 )

但是,让我们暂时忽略访问未初始化int的未定义行为。也许你今天感觉很幸运。也许您知道编译器将如何处理这种情况。

更准确地说,让我们对未定义的行为如何表现出一些合理的假设。

假设我们有:

int i;
i ++;

假设i的(未定义)初始值恰好是INT_MAX。然后递增i会导致有符号整数溢出,这也是明确未定义的行为(N1570 6.5第5段)。即使初始值小于INT_MAX,增加足够的时间也会导致溢出 - 而且由于您不知道初始值是什么,因此您不知道您有多少次可以安全地#34;增加它。

最可能的坏结果是优化编译器将以依赖于假设定义其行为的方式转换代码。这是一个不涉及未初始化变量的示例:

int i = INT_MAX;
int j = i + 1;
if (j > i) { /* ... */ }

如果add符合常见的环绕式2补码语义(C语言不保证 ,但通常是硬件中实现的那些),那么{{ 1}}将等于jINT_MIN将为false。逻辑上,(j > i) 必须为假,因为(j > i)值不能超过int。但由于INT_MAX设置为j,因此i + 1 必须为真(对于已定义行为的任​​何程序)。

无论您对此代码的行为有何期望,优化编译器都可能在法律上违反它们。如果您很幸运,它可能会在您破坏您的代码之前发出警告,但不需要这样做。

您在(j > i)的声明中添加= 0的时间要少得多,而不是我们讨论如果您不这样做会发生什么。 (但即便如此,如果你将i增加足够的次数以引起溢出,你可能会遇到问题。)

答案 1 :(得分:7)

当大多数人读到“这导致未定义的行为”时,他们最初会将其解释为“您感兴趣的变量的值是不确定的”。

这是错误的。

文本意味着它的含义:程序本身行为未定义。
如果他们想告诉你一个值是不确定的,那么他们会说这个值是不确定的。但他们没有。这些是不同含义的不同句子。

行为未定义时,表示程序 无意义 - 例如,变量可能不再是在您对其价值进行推断的时刻存在 该程序甚至可能没有执行您认为的代码。它可能只是跳到其他地方,它可能会突然删除磁盘上的文件,它可以做任何事情。质疑变量的值完全没有意义。

这与您的示例一样糟糕,因为虽然您可能希望它等同于i = 0,但会导致未定义的行为:< / p>

int i;
i -= i;

即,未定义的行为与任何特定变量的值无关。这是关于行为(动词),而不是数据(名词)。

答案 2 :(得分:2)

虽然“Undefined Behavior”很可能是变量中未定义的值,但是你不应该编写能够做出这种假设的代码。

其他一些海报通过提供删除主目录的极端示例来表明未定义的行为。我们都知道这个例子是极端的,但他们所提出的观点并不是极端的。

现实的未来“未定义的行为”可能是由增强的内存故障检查触发的分段错误。

由“Purify”等调试工具执行的内存故障检查可以检测到这些类型的错误。考虑到这些类型的工具可能演变为具有足够低的开销,并且它们将在生产代码中用于捕获这种“未定义的行为”,这并不是完全牵强的。

也就是说,对于未来的某些实现,“未定义的行为”将是一个分段错误。