I = f(); определяется, когда f изменяет i?
Связанный вопрос: Любая хорошая причина, почему оператор присваивания не является точкой последовательности?
Из comp.lang.c FAQ Я бы сделал вывод о том, что нижеприведенная программа undefined. Как ни странно, он только упоминает вызов f
как точку последовательности, между вычислением аргументов и передачей управления на f
. Передача управления из f
обратно вызывающему выражению не указана в качестве точки последовательности.
int f(void) { i++; return 42; }
i = f();
Действительно ли это undefined?
В качестве примечания, которое я добавляю ко многим из моих вопросов, меня интересует это в контексте статического анализа. Я сам не пишу это, я просто хочу знать, следует ли мне предупреждать об этом в программах, написанных другими.
Ответы
Ответ 1
Передача управления с f обратно на вызывающее выражение не указано как точка последовательности.
Да, это так.
в конце оценки полного выражения
Полное выражение, которое образует выражения или один из контролируя выражения if, переключатель, while, for или do/while или выражение в инициализатор или оператор return.
У вас есть оператор return, поэтому у вас есть точка последовательности.
Даже не кажется, что
int f(void) { return i++; } // sequence point here, so I guess we're good
i = f();
- undefined. (Который для меня довольно странный.)
Ответ 2
Это не undefined вообще. Одна из точек последовательности, перечисленных в Приложении C на C99, - это конец полного выражения, одним из которых является выражение в операторе return.
Поскольку вы возвращаете 42, есть точка последовательности сразу после этого оператора return
.
Для полноты здесь перечислены точки последовательности C99, а соответствующие значения выделены полужирным:
Ниже приведены точки последовательности, описанные в 5.1.2.3:
- Вызов функции после оценки аргументов (6.5.2.2).
- Конец первого операнда следующих операторов: логический AND && (6.5.13); логический ИЛИ || (6.5.14); условный? (6.5.15); запятая, (6.5.17).
- Конец полного декларатора: деклараторы (6.7.5);
- Конец полного выражения: инициализатор (6.7.8); выражение в выражении выражения (6.8.3); управляющее выражение оператора выбора (if или switch) (6.8.4); управляющее выражение while или do (6.8.5); каждое из выражений оператора for (6.8.5.3); выражение в операторе return (6.8.6.4).
- Непосредственно перед возвратом функции библиотеки (7.1.4).
- После действий, связанных с каждым преобразованием форматированных входных/выходных функций
спецификатор (7.19.6, 7.24.2).
- Непосредственно перед и сразу после каждого вызова функции сравнения и
также между любым вызовом функции сравнения и любым перемещением объектов
переданные в качестве аргументов для этого вызова (7.20.5).