Я был крайне удивлен тем, что компилируется следующий C-код:
int foo() {
int x = x;
return x;
}
Это гарантированно скомпилируется? Определено ли значение x после присвоения (во время тестирования в GCC оно было равно нулю)?
Я подозреваю, что он компилируется в GCC только в том случае, если вы установили очень мягкие уровни предупреждений. Другие компиляторы C, скорее всего, вернут постоянное значение для неинициализированной переменной или ловушки времени выполнения, если они вообще будут ее компилировать. Он может скомпилироваться, но его поведение все равно будет неопределенным.





Этот код имеет неопределенное поведение.
Символ x справа от =, выступающий в качестве инициализатора, сам по себе не инициализирован в момент его использования. Чтение неинициализированного значения, адрес которого никогда не был взят, приводит к неопределенному поведению согласно разделу 6.3.2.1p2 стандарта C:
За исключением случаев, когда это операнд оператора
sizeof,_Alignofоператор, унарный оператор&, оператор++, оператор--или левый операнд оператора.или оператора присваивания, lvalue, не имеющее типа массива, преобразуется в сохраненное значение. в обозначенном объекте (и больше не является lvalue); это называется преобразование значений. Если lvalue имеет уточненный тип, значение имеет неполная версия типа lvalue; кроме того, если lvalue имеет атомарный тип, значение имеет неатомарную версию тип lvalue; в противном случае значение имеет тип lvalue. Если lvalue имеет неполный тип и не имеет типа массива, поведение неопределенно. Если lvalue обозначает объект продолжительность автоматического хранения, которая могла бы быть объявлена с помощьюregisterкласс хранилища (его адрес никогда не фиксировался) и этот объект не инициализирован (не объявлен с инициализатором и без присвоения если оно было выполнено до использования), поведение не определено.
Согласно этому определению, объект не является неинициализированным, поскольку он объявлен с инициализатором, поэтому тот факт, что никакое присвоение не выполнялось, не имеет значения.
@Artyer Но x еще не инициализирован на момент чтения инициализатора.
Это не то, что говорится в цитате, но это кажется стандартным дефектом, потому что «неинициализированный» используется еще раз в примере 2 C2x §6.7.9 (Черновик: n3096), а double b = b*b; // undefined, uses uninitialized variable without address является примером.
gcc, без оптимизации — компилируется без нареканий, неопределенное значение, gcc O3 — компилируется без нареканий и значения нулевое, clang — компилируется с предупреждением о неинициализации