简体   繁体   English

在C中,是否可以增加未初始化的int?

[英]In C, is it ever O.K. to increment an uninitialized int?

According to this SO answer , incrementing an uninitialized int in C results in undefined behavior. 根据这个SO答案 ,在C中递增未初始化的int导致未定义的行为。 But what if I don't care at all about the initial value; 但是,如果我根本不在乎初始价值呢? for example, what if I just want an incrementing id? 例如,如果我只想要递增ID怎么办? Is this dangerous or bad practice for any reason? 这种危险不良做法是出于任何原因吗?

If the value of an object with automatic storage duration is accessed, and the object is uninitialized, the behavior is undefined. 如果访问具有自动存储持续时间的对象的值,并且该对象未初始化,则行为未定义。 This is explicitly and formally stated in N1570 6.3.2.1 paragraph 2 (that's the latest public draft of the ISO C standard). N1570 6.3.2.1第2段(这是ISO C标准的最新公开草案)中明确和正式地陈述了这一点。

" Undefined behavior " doesn't just mean that you might get any arbitrary value. 未定义的行为 ”并不仅仅意味着您可能获得任意值。 It means "behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements" ( N1570 3.4.3). 它表示“使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不对其施加任何要求”( N1570 3.4.3)。 The language standard says literally nothing about what accessing such an object's value means. 语言标准几乎没有说明访问这样一个对象的价值意味着什么。 It's effectively pure gibberish. 这实际上是纯粹的胡言乱语。 (The standard joke is that undefined behavior can cause demons to fly out of your nose. Of course in real life it can't -- but if it did you couldn't complain that the compiler is non-conforming.) (标准的笑话是,未定义的行为会导致恶魔飞出你的鼻子。当然,在现实生活中它不能 - 但如果它确实你不能抱怨编译器是不符合的。)

But let's ignore for a moment the undefined behavior of accessing an uninitialized int . 但是让我们暂时忽略访问未初始化的int的未定义行为。 Maybe you're feeling lucky today. 也许你今天感觉很幸运。 Maybe you know how your compiler will handle this case. 也许你知道你的编译器将如何处理这种情况。

More precisely, let's make some plausible assumptions about how that undefined behavior can manifest. 更准确地说,让我们对这种未定义的行为如何表现出一些合理的假设。

Suppose we have: 假设我们有:

int i;
i ++;

Suppose the (undefined) initial value of i happens to be INT_MAX . 假设i的(未定义的)初始值恰好是INT_MAX Then incrementing i causes a signed integer overflow, which again is explicitly undefined behavior ( N1570 6.5 paragraph 5). 然后递增i会导致有符号整数溢出,这也是明确未定义的行为( N1570 6.5第5段)。 Even if the initial value is less than INT_MAX , incrementing it enough times will cause an overflow -- and since you don't know what the initial value is, you don't know how many times you can "safely" increment it. 即使初始值小于INT_MAX ,增加足够的次数也会导致溢出 - 而且由于您不知道初始值是什么,因此您不知道可以“安全地”增加它的次数。

The most likely bad consequence is that an optimizing compiler will transform the code in ways that depend on the assumption that its behavior is defined. 最可能的坏结果是优化编译器将以依赖于其行为定义的假设的方式转换代码。 Here's an example not involving an uninitialized variable: 这是一个不涉及未初始化变量的示例:

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

If addition obeys the common wraparound 2's-complement semantics (which are not guaranteed by the C standard, but are commonly what's implemented in hardware), then j will be equal to INT_MIN , and (j > i) will be false. 如果add遵循常见的环绕式2的补码语义(C标准无法保证,但通常是硬件中实现的),则j将等于INT_MIN ,并且(j > i)将为false。 Logically, (j > i) must be false, because no int value can exceed INT_MAX . 逻辑上, (j > i) 必须为false,因为没有int值可以超过INT_MAX But since j was set to i + 1 , then (j > i) must be true (for any program that has defined behavior). 但由于j设置为i + 1 ,因此(j > i) 必须为真(对于任何已定义行为的程序)。

Whatever your expectations might be for the behavior of this code, an optimizing compiler may legally violate them. 无论您对此代码的行为有何期望,优化编译器都可能在法律上违反它们。 If you're lucky, it might warn you before breaking your code, but it's not required to. 如果你很幸运,可能会在破坏你的代码之前警告你,但不是必须的。

You'll spend far less time adding an = 0 to the declaration of i than we've spent discussing what happens if you don't. 你会花费更少的时间在i的声明中添加= 0而不是我们讨论如果不这样做会发生什么。 (But even then, you might run into problems if you increment i enough times to cause an overflow.) (但即使如此,你可以,如果你增加遇到问题i足够的时间,以导致溢出。)

When most people read "this results in undefined behavior" they initially interpret it as "the value of your-variable-of-interest is indeterminate". 当大多数人读到“这会导致未定义的行为”时,他们最初会将其解释为“你感兴趣的变量的价值是不确定的”。

This is wrong. 这是错的。

The text means literally what it means: the behavior of the program itself is undefined. 文本意味着字面意思: 程序本身行为是不确定的。
If they wanted to tell you that a value would be indeterminate, then they would say the value would be indeterminate. 如果他们想告诉你一个值是不确定的,那么他们会说这个值是不确定的。 But they didn't. 但他们没有。 These are different sentences with different meanings. 这些是具有不同含义的不同句子。

When the behavior is undefined, it means the program is meaningless -- for example, the variable may no longer even exist at the point at which you make an inference about its value. 行为未定义时,这意味着程序 没有意义 - 例如,变量可能不再存在于您对其值进行推断的位置。
The program may not even be executing the code you think it is. 该程序甚至可能没有执行您认为的代码。 It might just jump somewhere else, it might suddenly delete a file on your disk, it could do anything. 它可能只是跳到其他地方,它可能会突然删除磁盘上的文件,它可以做任何事情。 Questioning the value of the variable is completely missing the point. 质疑变量的值完全没有意义。

This is just as bad as your example, because while you might expect it to be equivalent to i = 0 , it also results in undefined behavior: 这与您的示例一样糟糕 ,因为虽然您可能期望它等于i = 0 ,但它也会导致未定义的行为:

int i;
i -= i;

ie, undefined behavior has nothing to do with the value of any particular variable. 即,未定义的行为与任何特定变量的值无关。 It's about behavior (verb), not data (noun). 这是关于行为 (动词),而不是数据 (名词)。

While the "Undefined Behavior" is very likely to be an undefined value in the variable in no way should you write code that would make that assumption. 虽然“未定义的行为”很可能是变量中未定义的值,但您不应该编写可以进行该假设的代码。

Some of the other posters are making the point of undefined behavior by giving an extreme example of deleting your home directory. 其他一些海报通过提供删除主目录的极端示例来表明未定义的行为。 We all know that the example is extreme, but the point they are making is not extreme. 我们都知道这个例子是极端的,但他们所提出的观点并不是极端的。

A realistic future "Undefined Behavior" could be a segmentation fault triggered by enhanced memory fault checking. 现实的未来“未定义的行为”可能是由增强的内存故障检查触发的分段故障。

Memory fault checking as performed by debugging tools such as "Purify" can detect these type of bugs. 通过调试工具(如“Purify”)执行的内存故障检查可以检测到这些类型的错误。 It is not completely far fetched to consider that these type of tools might evolve to have low enough overhead that they would be used in production code to trap such "Undefined Behavior". 考虑到这些类型的工具可能演变为具有足够低的开销以至于它们将在生产代码中用于捕获这种“未定义的行为”,这并不是完全牵强的。

That is, for some future implementations, the "Undefined Behavior" would be a segmentation fault. 也就是说,对于某些未来的实现,“未定义的行为”将是分段错误。

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

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