Неверный тип аргумента для стандартной функции библиотеки, определяемой как макрос

Вот пример кода:

#include <ctype.h>

int main(void)
{
    isalpha("X");
}

Мой вопрос: Является ли этот код нарушением ограничения? Эквивалентно, является ли внедрение несоответствующим, если он не выдает диагностику?


Мотивация. Несколько основных компиляторов не предупреждают об этом коде, даже в соответствии с кодом. C11 6.5.2.2/2 описывает, что передача char * функции с прототипом, ожидающим int является нарушением ограничения.

Однако мне непонятно, могут ли положения в 7.1.4 разрешить библиотечную функцию дополнительно определять как макрос, заменяя требование 6.5.2.2/2. Сноска 187 предполагает, что макрос скрывает прототип, но сноски являются ненормативными.

Код (isalpha)("X"); конечно, дает диагностику.

Ответы

Ответ 1

Я думаю, что ключом здесь является то, разрешено ли isalpha быть макросом или нет. C11 7.1.4 вкратце упоминается

Любая функция, объявленная в заголовке, может быть дополнительно реализована как функционально подобный макрос, определенный в заголовке

хотя эта глава в основном связана с именами коллизий и многопоточными проблемами и т.д. С другой стороны, C11 7.4 говорит:

Заголовок объявляет несколько функций, полезных для классификации и отображения символов.

и C11 7.4.1.2:

int isalpha(int c);

Функция isalpha...

Мое isalpha состоит в том, что isalpha следует рассматривать как функцию. При реализации в качестве макроса должна быть обеспечена определенная проверка типа.

Учитывая, что это функция, это довольно ясно. Для всех функций правила вызова функции указаны в C11 6.5.2.2:

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

Обратите внимание на часть "как по заданию". Это приводит нас к правилам простого назначения C11 6.5.16.1, ограничений. Код в вопросе за линиями будет эквивалентен выражению присваивания, такому как int c = (char[]){"X"}; где левый операнд является арифметическим типом, а правый операнд - указателем. Такой случай не может быть найден нигде в C11 6.5.16.1.

Поэтому код является нарушением ограничения 6.5.16.1.

Если компилятор lib хочет реализовать isalpha в качестве макроса и, таким образом, теряет способность проверки типа каким-либо образом, не выполняя нормальное преобразование параметров функции во время назначения, тогда эта библиотека может быть очень несовместимой, если компилятор не может создать диагностическое сообщение.

Ответ 2

Моя интерпретация заключается в том, что хотя стандарт требует наличия функции isalpha, в 7.1.4 он специально позволяет реализации дополнительно определять макрос с тем же именем, который скрывает объявление функции.

Это означает, что вызов isalpha в программе (без использования #undef) сначала может привести к расширению макроса к чему-то другому, кроме буквального вызова функции, для которого 6.5.2.2 потребует диагностики.