Требуется ли реализация C для игнорирования неопределенного поведения, возникающего во время оценки выражений void, как если бы сама оценка никогда не проводилась?
Учитывая C11, 6.3.2.2 §1:
Если выражение любого другого типа оценивается как недействительное, его значение или указатель отбрасываются. (Выражение void оценивается на предмет его побочных эффектов.)
Это связано с общей идиомой, используемой для предотвращения предупреждений компиляторов о неиспользуемых переменных:
void f() {
int a;
(void)a;
}
Но что, если у нас есть неопределенное поведение, например:
void f() {
int a;
(void)(1/0);
}
Могу ли я с уверенностью утверждать, что эта программа не содержит неопределенного поведения? В стандарте сказано, что «его значение или обозначение отбрасывается», но «выражение (...) оценивается (...)», поэтому оценка действительно имеет место.
GCC / Clang сообщает о неопределенном поведении, поскольку в этом случае это очевидно, но в более тонком примере они этого не делают:
int main() {
int a = 1;
int b = 0;
(void)(a/b);
return 0;
}
Даже с -O0
ни GCC, ни Clang не оценивают 1/0
. Но это также происходит даже без приведения к аннулированию, поэтому это не репрезентативно.
Доводя аргумент до крайности, не вызовет ли простая оценка (void)a
в моем первом примере (где a
неинициализировано) систематически неопределенное поведение?
В ISO C11 6.3.2.1 §2 упоминается, что:
Если lvalue обозначает объект с автоматической продолжительностью хранения, который можно было бы объявить с классом хранения регистров (адрес никогда не был взят), и этот объект не инициализирован (не объявлен с инициализатором и никакое присвоение ему не было выполнено до использования ) поведение не определено.
Однако в Приложении J.2 Неопределенное поведение формулировка немного отличается:
Поведение не определено в следующих случаях:
(...)
Lvalue, обозначающее объект с автоматической продолжительностью хранения, который мог быть объявлен с классом хранения регистров, используется в контексте, который требует значения указанного объекта, но объект не инициализирован. (6.3.2.1).
Это приложение действительно приводит к интерпретации, что выражение void
, содержащее неопределенное поведение во время его оценки, на самом деле не оценивается, но, поскольку это всего лишь приложение, я не уверен в его аргументативном весе.
(void)a
находится в серой зоне. 6.3.2.2: Если выражение любого другого типа оценивается как недействительное, его значение или указатель отбрасывается. (Выражение void оценивается на предмет его побочных эффектов.) - person Antti Haapala   schedule 24.07.2019https://www.godbolt.org/z/4tHKGg
: на самом деле выражение вычисляется частично, то есть функцияf
вызывается три раза, но деление и сложение в выражении не оцениваются (потому что результат игнорируется). Но ИМО компилятор может сгенерировать код для деления и добавления, а затем проигнорировать результат. - person Jabberwocky   schedule 24.07.2019