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

时间:2018-05-28 11:45:44

标签: c language-lawyer

以下是示例代码:

#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");确实提供了课程诊断。

2 个答案:

答案 0 :(得分: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中指定:

  

如果表示被调用函数的表达式具有包含原型的类型,   参数被隐式转换,就像通过赋值一样,转换为类型   相应的参数,将每个参数的类型作为不合格的版本   其声明的类型。

注意&#34;好像通过作业&#34;部分。这引出了我们对简单赋值C11 6.5.16.1,约束的规则。问题中的代码将在行后面等同于赋值表达式,例如int c = (char[]){"X"};,其中左操作数是算术类型,右操作数是指针。在C11 6.5.16.1中的任何地方都找不到这种情况。

因此,代码违反了6.5.16.1。

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

答案 1 :(得分:1)

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

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