【问题标题】:Wrong argument type to a standard library function defined as macro定义为宏的标准库函数的参数类型错误
【发布时间】:2018-11-07 00:09:21
【问题描述】:

这里是示例代码:

#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"); 代码当然会给出诊断。

【问题讨论】:

  • 我可以假设这与this question有关吗?
  • 仔细阅读,然后在 7.1.4 中有所关联,我们有“出于相同的句法原因,允许获取库函数的地址,即使它也被定义为宏。 185)”,其中 185 表示“这意味着实现应为每个库函数提供一个实际函数,即使它还为该函数提供了一个宏。”。同样,脚注不是规范性文本。但我想如果 int (*ptr)(int) = isalpha; 在不为问题中的代码提供诊断消息的编译器上编译,那么尝试一下会很有趣。
  • 如果它编译,那么如果你这样做int (*ptr)(int) = isalpha; ptr("X");会发生什么。
  • @Lundin 该声明显然会得到函数(没有参数列表时不会替换类似函数的宏)
  • 是的,如果您获得了该功能,您将获得检测违反简单分配的诊断能力。我的观点是,如果编译器仍然无法通过函数指针版本产生诊断,那么它肯定是坏的,因为我们可以忽略 7.1.4 所说的任何内容。我首先要做这个测试,检查某个编译器是否符合要求。

标签: c language-lawyer


【解决方案1】:

我认为这里的关键是是否允许将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 实现为宏,从而在赋值期间不执行函数参数的正常左值转换,从而以某种方式失去了类型检查能力,那么该库很可能是不合格的,如果编译器无法生成诊断消息。

【讨论】:

  • 请注意,这里有“一般安全”,例如宏没有序列点...
  • @AnttiHaapala 有人已经想到了。 7.1.4/3 “在库函数返回之前有一个序列点。”使库函数成为特例。
  • 脚注指出“一般安全”的意图是宏没有序列点。
  • @AnttiHaapala 我想 7.1.4/3 可能只应用 if 作为函数实现。但与脚注不同的是,它是规范性文本。我能想到的唯一原因是某些库可能确实将某些功能实现为宏。
  • 哦,顺便说一句,我猜脚注可能是关于在参数评估之后、调用函数之前的序列点。那是一个不同的序列点。
【解决方案2】:

我的解释是,虽然标准要求有一个isalpha 函数,但在 7.1.4 中,它特别允许实现额外定义一个同名的宏来隐藏函数声明。

这意味着允许在程序中调用isalpha(不首先调用#undef)导致宏扩展为文字函数调用以外的其他内容,6.5.2.2 需要对其进行诊断。

【讨论】:

    猜你喜欢
    • 2017-03-29
    • 2017-02-09
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    相关资源
    最近更新 更多