Гарантия неравенства указателей на стандартные функции?

Гарантирует ли язык C, что указатели на стандартные функции с разными именами должны сравниваться не одинаково?

Согласно 6.5.9 Операторы равенства, №6,

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

Кажется, я вспоминаю, что видел интерпретацию, утверждающую, что псевдонимы (множественные идентификаторы для "одной и той же функции") допустимы для стандартных функций, причем канонические кандидаты на такое обращение являются getc==fgetc а также putc==fputc; однако, я не знаю, где я мог это увидеть, и я скептически отношусь к этой концепции.

Есть ли официальное толкование или хорошо принятый аргумент за или против этой возможности?

2 ответа

Ну, вы попадаете в детали реализации. Стандарт только определяет поведение функций стандартной библиотеки.

За getc спецификация говорит (подчеркните мою):

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

Таким образом, реализация может реализовать getc как макрос, но он также может реализовать его как псевдоним (простой указатель на функцию) fgetc или как другая функция с таким же поведением. Короче говоря, вы не можете положиться на &getc == &fgetc быть правдой или ложью.


Единственное, что требует стандарт, это то, что '&getc` должно быть определено в 7.1.4 § 1:

... разрешено брать адрес библиотечной функции, даже если он также определен как макрос...

Это просто означает, что реализация должна иметь функцию с таким именем, но она может:

  • быть fgets функция - хорошо &fgetc == &getc правда
  • использовать макрос - fgetc == &getc ложно
  • позвонить fgets функция - &fgetc == &getc ложно

Нет, я не верю, что есть такая гарантия.

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

От C17 7.1.4:

Любая функция, объявленная в заголовке, может быть дополнительно реализована как функционально-подобный макрос, определенный в заголовке, поэтому, если библиотечная функция объявлена ​​явно, когда включен ее заголовок, один из методов, показанных ниже, может использоваться для обеспечения того, чтобы объявление не было пострадал от такого макроса. Любое макроопределение функции может быть подавлено локально, заключив имя функции в круглые скобки, потому что тогда за именем не следует левая скобка, которая указывает на расширение имени макрофункции. По той же синтаксической причине разрешается брать адрес библиотечной функции, даже если он также определен как макрос189).


189) Это означает, что реализация должна предоставлять фактическую функцию для каждой библиотечной функции, даже если она также предоставляет макрос для этой функции.

Текст продолжает описывать, как пользователи могут #undef имя макроса, если они хотят гарантировать, что они получают фактическую функцию.

Таким образом, реализация может иметь стандартную функцию и макрос с одинаковым именем. Но то, что макрос затем расширяется, определяется реализацией. Это вполне может быть внутренняя функция с тем же адресом, что и у другого макроса библиотеки.

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

В конкретном случае getcСтандарт гласит (C17 7.21.7.5):

Функция getc эквивалентна fgetc, за исключением того, что если она реализована как макрос, она может вычислять stream более одного раза, поэтому аргумент никогда не должен быть выражением с побочными эффектами.

Я бы сказал, что вполне вероятно, что реализация вызывает ту же самую фактическую функцию для fgetc а также getc когда они реализованы как макросы. (Или это atoi против strtol вызовите ту же функцию и т. д. и т. д.). Реализации стандартной библиотеки, на которые я заглянул, похоже, не делают этого, но я не думаю, что в стандарте есть что-то, что могло бы их остановить.


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

Другие вопросы по тегам