Использование неинициализированной переменной без вызова неопределенного поведения

Из 6.3.2.1 (выделено мной)

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

Это означает, что если автоматический объект не может быть объявлен с классом хранения регистра (занят его адрес):

int x; 

printf("just a dummy pointer print %p", &x);  //taking the address to break 6.3.2.1 UB condition

if (x == 2)
{
    print("x uninitialized value: %d", x);
} 

Чем согласно 6.3.2.1 в if (x == 2) нет поведения undefined, где я использую значение неинициализированного объекта. Если это правда, и здесь нет UB, то каково определенное поведение? что я должен ожидать в x по стандарту?


person user2162550    schedule 15.10.2019    source источник
comment
Может быть, мы могли бы дать объективные ответы, если бы вы поместили цитируемый раздел в контекст? Например, что означает «поведение»?   -  person Adrian Mole    schedule 15.10.2019
comment
@ Адриан, это стандарт C, а не какая-то экзотическая книга.   -  person Federico klez Culloca    schedule 15.10.2019
comment
Чем 6.3.2.1 не актуален Так? Это не исключает неопределенного поведения по другим причинам. Это все равно, что сказать полицейскому, который остановил вас за проезд на красный свет, но я не превышал скорость!   -  person Andrew Henle    schedule 15.10.2019
comment
Обратите внимание, что вам не нужно печатать указатель. Просто ничего не делающего оператора, такого как &x;, достаточно, чтобы выполнить условие, чтобы оно не было UB.   -  person R.. GitHub STOP HELPING ICE    schedule 15.10.2019
comment
Для вас и многих других абсолютных профессионалов может быть нормальным знать, что вы имеете в виду под 6.3.2.1 (выделено мной), но можете ли вы дать абсолютную ссылку на то, что вы имеете в виду? Это реализация ANSI-C?   -  person RobertS supports Monica Cellio    schedule 15.10.2019
comment
@RobertS c11 port70.net/~nsz/c/c11/ n1570.html#6.3.2.1p2   -  person user2162550    schedule 15.10.2019
comment
@ user2162550 спасибо ;-).   -  person RobertS supports Monica Cellio    schedule 15.10.2019


Ответы (2)


В этом случае, поскольку адрес x был занят, поведение не является строго неопределенным. Значение x в этот момент неопределенно. Это означает, что значение является либо представлением-ловушкой, либо неуказанным.

Если x содержит представление ловушки, то поведение не определено, в противном случае значение не указано, что означает, что может быть напечатано любое допустимое значение.

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

Соответствующие отрывки из стандарта C:

Раздел 3.19:

3.19.2

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

3.19.3

1 unspecified value действительное значение соответствующего типа, если настоящий международный стандарт не налагает требований, на какое значение выбирается в любом случае

2 ПРИМЕЧАНИЕ. Неуказанное значение не может быть представлением прерывания.

3.19.4

1 представление ловушки представление объекта, которое не обязательно должно представлять значение типа объекта

Раздел 6.7.9p10:

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

person dbush    schedule 15.10.2019
comment
Обратите внимание, что в типичных реальных реализациях биты заполнения отсутствуют, а целые типы имеют полнодиапазонное представление с дополнением до двух, а это означает, что представления ловушки не существуют. Эти свойства можно измерить/наблюдать с помощью макросов limits.h и другими способами. - person R.. GitHub STOP HELPING ICE; 15.10.2019
comment
Верните биты четности! - person Eric Postpischil; 15.10.2019

Стандарт использует термин «неопределенное поведение», среди прочего, для описания общих ситуаций, когда подавляющее большинство реализаций будут вести себя одинаково предсказуемо, но где некоторые конкретные реализации могут лучше служить своим клиентам, ведя себя по-другому.

Рассмотрим следующую функцию:

struct foo { unsigned char dat[256]; };

struct foo x,y;

void test(int a, int b)
{
  struct foo temp;
  temp.dat[a] = 1;
  temp.dat[b] = 2;
  x=temp;
  y=temp;
}

Я не думаю, что авторы стандарта хотели требовать, чтобы программисты полностью инициализировали temp перед его сохранением, но я также не думаю, что они хотели запретить реализациям просто записывать в x.dat[a], y.dat[a], x.dat[b] и y.dat[b], оставляя при этом другие элементы этих структур, удерживающие то, что они держали ранее. Вместо того, чтобы пытаться точно определить, какие виды оптимизации должны быть разрешены, они просто предположили, что реализации будут стремиться наилучшим образом удовлетворить потребности своих клиентов.

person supercat    schedule 15.10.2019