错误的参数类型为定义为宏的标准库函数

这是示例代码:

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

我的问题是:此代码是违反约束的吗? 同样,如果不执行诊断,是不符合的实现吗?


动机:即使在符合规范的代码中,多个主要编译器也不会对此代码发出警告。 C11 6.5.2.2/2涵盖了将char *传递给具有原型期望int的函数是违反约束的情况。

但是,我不清楚7.1.4中允许将库函数另外定义为宏的规定是否取代了6.5.2.2/2的要求。 脚注187表明该宏隐藏了原型,但脚注是非规范性的。

代码(isalpha)("X"); 确实给出了诊断。

我认为这里的关键是是否允许将isalpha定义为宏。 C11 7.1.4简要提及

在头中声明的任何函数可以另外实现为在头中定义的类似函数的宏

虽然本章主要涉及命名冲突和multithreading问题等。另一方面,C11 7.4说:

标头声明了几个对字符分类和映射有用的函数。

和C11 7.4.1.2:

int isalpha(int c);

isalpha函数……

我认为isalpha应被视为一种function。 或者,如果实现为宏,则必须通过实现来确保某种类型的检查。

鉴于它是一个function,从那里很清楚。 对于所有函数,函数调用的规则在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实现为宏,从而通过在赋值期间不执行函数参数的正常左值转换而以某种方式失去类型检查能力,那么如果编译器无法生成,则该库很可能是不符合的。诊断信息。

我的解释是,尽管标准要求存在isalpha函数,但在7.1.4中它特别允许实现另外定义一个具有隐藏函数声明的相同名称的宏。

这意味着在程序中调用isalpha (首先没有#undef )允许导致宏扩展到除6.5.2.2需要诊断的文字函数调用之外的其他东西。