Проверка существования внешне определенных идентификаторов в C - PullRequest
0 голосов
/ 12 октября 2010

Я столкнулся с этой проблемой при разработке в Objective-C для iOS, но это должно относиться к любому коду C / C ++ / Objective-C, использующему компоновщик Mac OS X / iOS. Решение покрыто другим вопросом , но меня интересует почему .

Допустим, я использую ссылку на библиотеку, которая определяет константу. В заголовочном файле есть объявление вроде этого:

extern char * const BrandNewIdentifier;

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

Теперь, если есть функция, которая определена только в самой последней версии библиотеки, я могу сделать это:

if (BrandNewFunc) {
    BrandNewFunc("foobar", 42);
} else {
    printf("Your system does not support some thing.");
}

Вместо того, чтобы содержать адрес кода функции, BrandNewFunc оценивается как NULL. Я бы подумал, что константа будет вести себя так же, но если я попробую тот же шаблон, приложение умирает при выполнении проверки (выбрасывает EXC_BAD_ACCESS на iOS). В частности:

if (BrandNewIdentifier) ... // blows up here

Вместо этого проверяется адрес идентификатора:

if (&BrandNewIdentifier) {
    printf("You got it!");
}

Я вижу логику: BrandNewIdentifier не имеет значения, поэтому доступ к нему должен завершиться неудачей. Но тогда почему этот синтаксис работает в случае BrandNewFunc? Разве я не обязан также проверять его адрес? Или это действительно непротиворечиво, и я что-то упустил из виду?

1 Ответ

2 голосов
/ 12 октября 2010

Соответствующей частью стандарта C является раздел 6.3.2.1 «L-значения, массивы и обозначения функций». Вот что говорится о функциях:

A обозначение функции - это выражение, имеющее тип функции. За исключением случаев, когда это операнд оператора sizeof 65 или унарный оператор &, указатель функции с функцией типа '', возвращающей тип '', преобразуется в выражение с указателем типа '' на функцию, возвращающую тип ''.

[сноска 65] Поскольку это преобразование не происходит, операнд оператора sizeof остается обозначением функции и нарушает ограничение в 6.5.3.4. [Ed: ограничение в 6.5.3.4 говорит, что вы не можете применять sizeof для обозначения функции - это семантическая ошибка].

Идентификатор, который называет функцию, является простейшим видом «выражения, имеющего тип функции». Так что это означает, что если foo было объявлено как функция, идентификатор foo оценивается как указатель на эту функцию, за исключением , когда это операнд & (в этом случае большее выражение &foo оценивается как указатель на эту функцию) или операнд sizeof (в этом случае большее выражение, sizeof(foo), вызывает ошибку компиляции).

tl, dr: Когда foo является функцией, foo и &foo эквивалентны по определению. Это специальное правило для функций. Это не совсем похоже на специальное правило для массивов, которое также «затухает» для указателей во многих контекстах (это правило на один абзац выше того, которое я цитировал).

В сторону: Да, это означает, что оператор вызова функции всегда работает с указателем на функцию. Когда pfunc является переменной-указателем на функцию, (*pfunc)() обрабатывается так, как если бы она читала (&(*pfunc))() ... или просто pfunc().

...