Why uninitialized instead of out-of-bounds? Why uninitialized instead of out-of-bounds? c c

Why uninitialized instead of out-of-bounds?


I believe this could be the case here: in the first code, GCC notices that you don't need the entire char array at all, just b[9], so it can replace the code with

char b_9; // = ???printf("b[9] = %d\n", b_9);

Now, this is a completely legal transform, because as the array was accessed out of bounds, the behaviour is completely undefined. Only in latter phase does it then notice that this variable, which is a substitute for b[9], is uninitialized, and issues the diagnostics message.

Why I believe this? Because if I add just any code that will reference the array's address in memory, for example printf("%p\n", &b[8]); anywhere, the array now is fully realized in memory, and compiler will diagnose array subscript is above array bounds.


What I find even more interesting is that GCC does not diagnose out-of-bounds access at all unless optimizations are enabled. This would again suggest that whenever you're writing a program new program you should compile it with optimizations enabled to make the bugs highly visible instead of keeping them hidden with debug mode ;)


The behaviour on reading b[9] or b[10] is undefined.

Your compiler is issuing a warning (it doesn't have to), although the warning text is a little misleading, but not technically incorrect. In my opinion, it's rather clever. (A C compiler is not required to issue a diagnostic for out of bounds access.)

Regarding &b[9], the compiler is not allowed to dereference that, and must evaluate it as b + 9. You are allowed to set a pointer one past the end of an array. The behaviour of setting a pointer to &b[10] is undefined.


Some additional experimental results.


Using char b[9] instead of char b[] appears to make no difference, gcc still warns the same with char b[9].

Interestingly, initializing the one-passed element via the "next" member in a struct 1) does quiet the "uninitialized" warning and 2) does not warn about accessioning outside the array.

#include <stdio.h>typedef struct {  char c[9];  char d[9];} TwoNines;int main(void) {  char b[9] = { 'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!' };  printf("b[] size %zu\n", sizeof b);  printf("b[9] = %d\n", b[9]);   // 'b[9]' is used uninitialized in this function [-Wuninitialized]  TwoNines e = { { 'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!' }, //                 { 'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!' } };  printf("e size %zu\n", sizeof e);  printf("e.c[9] = %d\n", e.c[9]);   // No warning.  return 0;}

Output

b[] size 9b[9] = 0e size 18    // With 18, we know `e` is packed.e.c[9] = 78  // 'N'

Notes:
gcc -std=c11 -O3 -g3 -pedantic -Wall -Wextra -Wconversion -c -fmessage-length=0 -v -MMD -MP ...
gcc/gcc-7.3.0-2.i686