简体   繁体   中英

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. But what if I don't care at all about the initial value; for example, what if I just want an incrementing 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).

" 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). 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 . 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 . Then incrementing i causes a signed integer overflow, which again is explicitly undefined behavior ( N1570 6.5 paragraph 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.

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. Logically, (j > i) must be false, because no int value can exceed INT_MAX . But since j was set to i + 1 , then (j > i) must be true (for any program that has defined behavior).

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. (But even then, you might run into problems if you increment i enough times to cause an overflow.)

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:

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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