Intereting Posts

Любые гарантии для неинициализированных переменных?

Существует много утверждений о том, что любое использование неинициализированных переменных вызывает неопределенное поведение (UB) .
Просматривая документы, я не мог проверить это требование, поэтому я хотел бы получить убедительный аргумент, разъясняющий это как для C, так и для C ++.
Я ожидаю ту же семантику для обоих, но я готов удивляться тонким или не очень тонким различиям.

Некоторые примеры использования неинициализированных переменных для начала. Пожалуйста, добавьте других, если необходимо, чтобы объяснить любые угловые случаи, которые они не покрывают.

void test1() { int x; printf("%d", x); } void test2() { int x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%d", x); } void test3() { unsigned x; printf("%u", x); /* was format "%d" */ } void test4() { unsigned x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%u", x); /* was format "%d" */ } 

В C все они являются неопределенным поведением, но по той причине, что, вероятно, не приходит прямо в голову. Доступ к объекту с неопределенным значением имеет неопределенное поведение, если оно «без памяти», то есть 6.3.2.1 p2

Если lvalue обозначает объект с продолжительностью автоматического хранения, который мог быть объявлен с classом хранения регистров (никогда не был принят его адрес), и этот объект не инициализирован (не объявлен с инициализатором, и его назначение не было выполнено до использования ), поведение не определено.

В противном случае, если адрес сделан, интерпретация того, что неопределенный означает конкретно в этом случае, не является единодушным. Есть люди, которые ожидают, что такое значение будет исправлено после его первого чтения, другие говорят о чем-то вроде «woobly» (или так) значений, которые могут быть разными при каждом доступе.

Таким образом, не делайте этого. (Но вы, наверное, уже знали.)

(И не говоря о ошибке, используя «% d» для unsigned .)

С

C11 6.7.9 / 10

Если объект, который имеет автоматическую продолжительность хранения, не инициализируется явно, его значение является неопределенным.

Неопределенные значения обрабатываются следующим образом:

C11 6.2.6.1/5

Определенные представления объектов не должны представлять значение типа объекта. Если хранимое значение объекта имеет такое представление и считывается выражением lvalue, которое не имеет типа символа, поведение не определено. Если такое представление создается побочным эффектом, который изменяет всю или любую часть объекта выражением lvalue, которое не имеет типа символа, поведение не определено 50). Такое представление называется ловушечным представлением.

В приведенном выше нормативном тексте есть комментарий:

50) Таким образом, автоматическая переменная может быть инициализирована в представление ловушки без возникновения неопределенного поведения, но значение переменной не может использоваться до тех пор, пока в ней не будет сохранено правильное значение.

(акцент мой)

Кроме того, смещение влево знаковой переменной int, содержащей неопределенное значение, также может приводить к неопределенному поведению, если оно интерпретируется как отрицательное:

C11 6.5.7 / 4

Результат E1 << E2 - это E1 левые сдвиговые позиции E2; освобожденные биты заполняются нулями. Если E1 имеет неподписанный тип, значение результата равно E1 × 2E2, уменьшенному на единицу больше, чем максимальное значение, представляемое в типе результата. Если E1 имеет подписанный тип и неотрицательное значение, а E1 × 2E2 представляется в типе результата, то это результирующее значение; в противном случае поведение не определено.

Все четыре случая ссылаются на неопределенное поведение в C, так как неинициализированная автоматическая переменная никогда не имеет своего адреса. См. Другой ответ.

Кстати, sizeof(x) определяется, поскольку выражение фактически не оценивается: это оценка времени компиляции, которая распадается на тип.

В последнем проекте C ++ 1y ( N3936 ) это явно неопределенное поведение, так как язык неопределенных значений и неопределенное поведение были выяснены, и теперь он говорит в разделе 8.5 :

[…] Если неопределенное значение создается путем оценки, поведение не определено, за исключением следующих случаев;

и переходит к исключению списка только для некоторых неподписанных типов узких символов .

Раньше в C ++ нам приходилось полагаться на переопределенное преобразование lvalue-to-rvalue, чтобы доказать неопределенное поведение, что является проблематичным в общем случае. В этом случае мы имеем преобразование lalue-to-rvalue. Если мы посмотрим на раздел 5.2.2 Вызов функции 7, который гласит ( акцент мой ):

Если для данного аргумента нет параметра, аргумент передается таким образом, что получающая функция может получить значение аргумента, вызвав va_arg (18.10). […] Стандартные преобразования lvalue-to-rvalue (4.1) , стандартное преобразование от массива к указателю (4.2) и стандартного преобразования функции-to-pointer (4.3) выполняется в выражении аргумента .

Что касается C, поведение всех примеров может быть неопределенным:

Глава и стих

3.19.2
1 неопределенное значение
либо неопределенное значение, либо ловушечное представление

6.2.6. Представления типов
6.2.6.1 Общие положения

5 Некоторые представления объектов не должны представлять значение типа объекта. Если хранимое значение объекта имеет такое представление и считывается выражением lvalue, которое не имеет типа символа, поведение не определено. Если такое представление создается побочным эффектом, который изменяет всю или любую часть объекта с помощью выражения lvalue, которое не имеет типа символа, поведение не определено. 50). Такое представление называется ловушечным представлением.

50) Таким образом, автоматическая переменная может быть инициализирована в представление ловушки без возникновения неустановленного поведения, но значение переменной не может использоваться до тех пор, пока в ней не будет сохранено правильное значение.

Во всех четырех случаях x имеет автоматическую продолжительность хранения и явно не инициализируется, то есть его значение неопределенно; если это неопределенное значение является ловушечным представлением, то поведение не определено.

РЕДАКТИРОВАТЬ

Удалена ссылка на приложение J, так как оно ненормативно.