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

M.M*_*M.M 12 c language-lawyer

这是示例代码:

#include <ctype.h>

int main(void)
{
    isalpha("X");
}
Run Code Online (Sandbox Code Playgroud)

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


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

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

该代码(isalpha)("X");确实提供了诊断.

Lun*_*din 2

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

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

虽然本章主要关注命名冲突和多线程问题等。另一方面,C11 7.4 说:

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

和 C11 7.4.1.2:

int isalpha(int c);

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 的约束。

如果编译器库选择实现isalpha为宏,从而在分配期间不执行函数参数的正常左值转换,从而以某种方式失去类型检查能力,那么如果编译器无法生成诊断信息,则该库很可能是不合格的信息。