Подтвердить что ты не робот

I = f(); определяется, когда f изменяет i?

Связанный вопрос: Любая хорошая причина, почему оператор присваивания не является точкой последовательности?

Из comp.lang.c FAQ Я бы сделал вывод о том, что нижеприведенная программа undefined. Как ни странно, он только упоминает вызов f как точку последовательности, между вычислением аргументов и передачей управления на f. Передача управления из f обратно вызывающему выражению не указана в качестве точки последовательности.

int f(void) { i++; return 42; }
i = f();

Действительно ли это undefined?

В качестве примечания, которое я добавляю ко многим из моих вопросов, меня интересует это в контексте статического анализа. Я сам не пишу это, я просто хочу знать, следует ли мне предупреждать об этом в программах, написанных другими.

4b9b3361

Ответ 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).