Позвольте мне привести аргумент, почему я думаю, что это все еще не определено.
Во-первых, респонденты, говорящие, что это "в основном определено" или что-то подобное, основанное на их опыте работы с некоторыми компиляторами, просто ошибаются.Небольшая модификация вашего примера будет служить для иллюстрации:
#include <stdio.h>
int
main()
{
int v;
scanf("%d", &v);
if (v != 0)
{
printf("Hello\n");
int *p;
*p = v; // Oops
}
return v;
}
Что делает эта программа, если вы вводите «1» в качестве ввода?Если вы ответите «Это печатает Hello, а затем падает», вы ошибаетесь.«Неопределенное поведение» не означает, что поведение некоторого конкретного утверждения не определено;это означает, что поведение всей программы не определено.Компилятору разрешается предполагать, что вы не участвуете в неопределенном поведении, поэтому в этом случае он может предполагать, что v
не равен нулю и просто не генерирует какой-либо код в скобках, включая printf
.
Если вы считаете, что это маловероятно, подумайте еще раз.GCC может не выполнять этот анализ точно, но он выполняет очень похожие.Мой любимый пример, который на самом деле иллюстрирует суть на самом деле:
int test(int x) { return x+1 > x; }
Попробуйте написать небольшую тестовую программу для распечатки INT_MAX
, INT_MAX+1
и test(INT_MAX)
.(Обязательно включите оптимизацию.) Типичная реализация может показывать INT_MAX
для 2147483647, INT_MAX+1
для -2147483648 и test(INT_MAX)
для 1.
Фактически, GCC компилирует эту функцию ввернуть константу 1. Почему?Поскольку целочисленное переполнение является неопределенным поведением, поэтому компилятор может предположить, что вы этого не делаете, поэтому x не может быть равен INT_MAX
, поэтому x+1
больше x
, поэтому эта функция может возвращать 1 безоговорочно.
Неопределенное поведение может привести и приводит к переменным, которые не равны самим себе, отрицательные числа, которые сравниваются с большими, чем положительные числа (см. Пример выше), и другое странное поведение.Чем умнее компилятор, тем более странным является его поведение.
Хорошо, я признаю, что не могу процитировать главу и стих стандарта, чтобы ответить на конкретный вопрос, который вы задали.Но люди, которые говорят: «Да, да, но в реальной жизни разыменование NULL просто вызывает ошибку сегмента» более ошибочно, чем они могут себе представить, и они ошибаются с каждым поколением компилятора.
И в реальной жизни,если код мертв, вы должны удалить его;если он не мертв, вы не должны вызывать неопределенное поведение.Вот мой ответ на ваш вопрос.