Каковы последствия точки следования непосредственно перед возвратом из библиотечной функции?

В этом недавнем вопросе было показано, что некоторый код имеет неопределенное поведение:

a[++i] = foo(a[i-1], a[i]);

потому что даже несмотря на то, что фактический вызов foo() является точкой последовательности, назначение не упорядочено, так что вы не Неизвестно, вызывается ли функция после того, как произошел побочный эффект ++i, или до этого.

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

int y = 1;
int func1(int x) { return x + y; }
int main(void)
{
    int result = func1( y++ ); // guaranteed to be 3
}

Но глядя на стандарт, есть также §7.1.4 p3 (в главе о стандартной библиотеке):

Существует точка следования непосредственно перед возвратом из библиотечной функции.

Мой вопрос здесь таков: каковы последствия этого абзаца? Почему это касается только библиотечных функций и какой код на самом деле будет полагаться на это?

Простые идеи, такие как (бессмысленный код, которому нужно следовать)

errno = 0;
long result = ftell(file) * errno;

по-прежнему будет неопределенным, так как на этот раз умножение не упорядочено. Я ищу пример, который использует эту специальную гарантию §7.1.4 p3 для библиотечных функций.


Что касается предлагаемого дубликата, точка последовательности после оператора return?, это действительно тесно связано, и я нашел его, прежде чем задать этот вопрос . Это не дубликат, потому что

  • он спрашивает о нормативном тексте, утверждающем, что есть точка следования сразу после return, не спрашивая о последствиях, когда она есть.
  • в нем упоминается только специальное правило для библиотечных функций, о котором этот вопрос, без дальнейшего уточнения.

Следовательно, на мои вопросы здесь нет ответа там. Принятый ответ использует возвращаемое значение в выражении без последовательности (в данном случае дополнение) и объясняет, как результат зависит от последовательности этого добавления, обнаруживая только это, если бы вы знали последовательность добавления, весь результат будет определяться точкой следования сразу после return. Он не показывает пример кода, который фактически определен из-за этого правила, и ничего не говорит о том, чем и почему библиотечные функции являются особенными.


person Community    schedule 22.08.2017    source источник
comment
стандартный отказ от ответственности: если вы понизите голос, потому что я упустил что-то очевидное, пожалуйста, оставьте комментарий, чтобы указать на это, спасибо.   -  person    schedule 22.08.2017
comment
Возможный дубликат точки последовательности после оператора return?   -  person Michael Foukarakis    schedule 22.08.2017
comment
@MichaelFoukarakis Я проверил это, оно тесно связано, но не отвечает на этот вопрос. Хотя там упоминается правило специальной библиотечной функции, нет примера кода, в котором это правило действительно имеет какое-либо действие.   -  person    schedule 22.08.2017
comment
Практическое использование этого оператора, когда многопоточность используется в программе.   -  person haccks    schedule 22.08.2017
comment
@hackks Думаю, должно быть что-то еще, так как тот же абзац уже есть в C99.   -  person    schedule 22.08.2017


Ответы (1)


Библиотечные функции не имеют реализующего их кода, охватываемого стандартом (они могут быть даже не реализованы на C). Стандарт определяет только их поведение. Таким образом, положение об операторах return не распространяется на реализацию библиотечных функций.

Цель этого пункта (в сочетании с наличием точки последовательности при входе в библиотечную функцию) состоит в том, чтобы сказать, что любые побочные эффекты библиотечных функций упорядочены либо до, либо после любых других вычислений, которые могут быть в коде, который вызывает библиотечная функция.

Таким образом, пример в вашем вопросе не является неопределенным поведением (если только умножение не переполняется!): чтение errno либо упорядочено до, либо после модификации ftell, не указано, что именно.

person M.M    schedule 22.08.2017
comment
Ах, тонкая разница между неопределенным и неопределенным ... Я склонен использовать их слишком небрежно, я думаю. Спасибо! (разве ваш пример не определен для чего-то совершенно другого: подписанное переполнение?) - person ; 22.08.2017
comment
@FelixPalmen Я изменил свой ответ, чтобы использовать ваш пример, в моем исходном примере я не думаю, что было подписанное переполнение, но если бы оно было, то это отвлекло бы от моей точки зрения, поэтому ваш пример все равно лучше - person M.M; 22.08.2017
comment
Ну, было, strtol вернуло бы LONG_MAX, а ERANGE положительно :) По крайней мере, ваш первый абзац очень логично объясняет, почему библиотечные функции здесь особенные, спасибо и уф :) - person ; 22.08.2017