Позвольте мне привести аргумент, почему я думаю, что это все еще не определено.
Во-первых, ответчики, говорящие, что это «в основном определено» или что-то в этом роде, основываясь на своем опыте работы с некоторыми компиляторами, просто ошибаются. Небольшая модификация вашего примера будет служить иллюстрацией:
#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 просто приводит к ошибке seg», ошибаются больше, чем они могут себе представить, и с каждым поколением компиляторов они ошибаются все больше.
И в реальной жизни, если код мертв, вы должны удалить его; если он не мертв, вы не должны вызывать неопределенное поведение. Таков мой ответ на ваш вопрос.
person
Nemo
schedule
01.11.2011
v
равно нулю, ошибочный фрагмент кода не выполняется. - person Matteo Italia   schedule 01.11.2011int a, b, c; scanf("%d", "%d", &a, &b); c=a+b;
. Этот код действителен? Вы бы так сказали, но в определенных обстоятельствах (когда a+b переполняется) это демонстрирует неопределенное поведение. Означает ли это, что программа в целом недействительна ни при каких обстоятельствах? - person Matteo Italia   schedule 01.11.2011malloc
или аналогичные проблемы (UB вызывается при разыменовании указателя только еслиmalloc
вернул 0). - person R.. GitHub STOP HELPING ICE   schedule 01.11.2011