如何解决哪些 C 规则允许在函数声明器中使用标识符,该标识符以前定义为类型?
考虑这个代码(t0.c):
typedef int T;
void f(int T);
调用:
gcc -std=c11 -Wall -Wextra -pedantic -c t0.c
<nothing>
clang -std=c11 -Wall -Wextra -pedantic -c t0.c
<nothing>
cl /std:c11 /Za /c t0.c
t0.c(2): warning C4224: nonstandard extension used: formal parameter 'T' was prevIoUsly defined as a type
问题:
- 哪些 C 规则允许在函数声明器中使用标识符,该标识符以前定义为类型?
- 如果 msvc 说
nonstandard extension
,那么为什么符合标准的 gcc / clang 什么也没说?
解决方法
1
- 哪个 C 规则允许在函数声明器中使用标识符,该标识符以前定义为类型?
首先,typedef
名称是一个标识符。 C 2018 6.2.1 1 说:
一个标识符可以表示一个对象;一个函数;结构、联合或枚举的标记或成员;一个 typedef 名称;标签名称;宏名称;或宏参数...
同一个段落说我们可以使用相同的标识符来表示不同的实体:
…相同的标识符可以表示程序中不同点的不同实体…
第 4 段告诉我们在函数原型中声明的 T
隐藏了之前的 T
:
... 在内部作用域内,标识符指定在内部作用域中声明的实体;在外部作用域中声明的实体在内部作用域中隐藏(并且不可见)。
2
- 如果 msvc 说非标准扩展,那么为什么符合标准的 gcc / clang 什么也没说?
GCC 和 Clang 什么都没说,因为按照 C 标准代码是没问题的,而且它们的实现者没有选择发出任何警告。
C 标准允许 MSVC 报告超出标准要求的诊断,因为所有 C 实现都是如此,但声称它是非标准扩展是不正确的。
,C17 6.2.1/2:
由相同标识符指定的不同实体要么具有不同的作用域,要么位于不同的名称空间中。作用域有四种:函数、文件、块和函数原型。
C17 6.2.1/4:
每个其他标识符的范围由其声明的位置决定(在声明符或类型说明符中)。如果声明标识符的声明符或类型说明符出现在任何块或参数列表之外,则标识符具有文件范围,该范围在翻译单元的末尾终止。
如果声明标识符的声明符或类型说明符出现在块内或函数定义的参数声明列表内,则标识符具有块作用域,它在相关块的末尾终止。
如果声明标识符的声明符或类型说明符出现在函数原型的参数声明列表中(不是函数的一部分)
定义),标识符具有函数原型作用域,它在函数声明符的末尾终止。
您的 typedef 位于文件范围内,但参数位于函数原型范围内。另见 6.2.3 关于标识符的命名空间。这些是“普通标识符”,因此内部作用域始终优先于外部作用域。
如果 msvc 说非标准扩展,那为什么符合标准的 gcc / clang 什么也没说?
据说是因为 MSVC 不好、不合规并且已知会给出错误的诊断。
,您显示的代码等效于
typedef int T;
void f(int);
也许你想要
typedef int T;
void f(int T) {
(void)T; // ignore unused parameter
}
gcc ... -Wshadow ...
和 clang ... -Weverything ...
为其发出诊断信息(gcc v6.3.0;clang v3.8.1)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。