Is a variable declared in a loop body preserved du

2019-07-20 03:36发布

Consider a loop in C which declares a character array in the loop's body. At each iteration, a character of array is modified until the end is reached. At the end, the variable is printed. The description would expand to the next code:

#include <stdio.h>

int main(void) {
    int i = 0;
    for (;;) {/* same as: while(1) { */
        char x[5];
        x[i] = '0' + i;
        if (++i == 4) {
            x[i] = '\0'; /* terminate string with null byte */
            printf("%s\n", x);
            break;
        }
    }
    return 0;

Many may expect 0123 as output. But for some reason GCC 4.7 does not do that when compiling with optimization enabled (-O1 and higher). It instead puts random data in the first bytes of the character array, which becomes:

| 0  |  1  |  2  |  3  |  4   |
|     RANDOM     | '3' | '\0' |

I think that this is logical behaviour from the language point of view: automatic variables are gone after a block is terminated, so the above "random" behaviour should be expected.

What should be the correct behaviour? I know that moving the declaration of x outside the loop "fixes" it, but that does not say anything about the behaviour of this snippet. The real-world problem is a bug in Netfilter.

4条回答
走好不送
2楼-- · 2019-07-20 04:09

This is a matter of block scope. The loop body is a block, denoted by {}, which is entered and left in every loop iteration. Every time the block is entered, you get (conceptually) a new x with unspecified contents.

Since you've only set x[3] = '3' and x[4] = '\0' in the iteration where printf is called, only those two array members have well-defined content. The rest may contain anything, including '\0', so printf may output any string of length at most 2, optionally followed by any other character and 3.

查看更多
等我变得足够好
3楼-- · 2019-07-20 04:11

Since the array is declared inside the scope of loop's body, you can think of it as of a new array being allocated in the automatic storage area for each loop iteration. The content of that unititialized array is undefined, except for the character at the index to which you have assigned during the current iteration, so what you see there is indeterminate value:

C99 standard, section 6.7.8: If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate

When optimization is turned off, the array lands in the same spot in the automatic storage, so your program gets lucky; however, this is by no means guaranteed.

Move the array to outside the loop, like this:

int i = 0;
char x[5];
for (;;) {
    x[i] = '0' + i;
    if (++i == 4) {
        x[i] = '\0'; /* terminate string with null byte */
        printf("%s\n", x);
        break;
    }
}
查看更多
看我几分像从前
4楼-- · 2019-07-20 04:15

This would output as expected (a random character array), as an auto-variable is cleaned up after the scope in which it is declared terminates. To fix, move x outside of the scope of the for loop.

查看更多
Fickle 薄情
5楼-- · 2019-07-20 04:21

The array will be allocated memory for each iteration and it will have the value gained in the last iteration only.

查看更多
登录 后发表回答