繁体   English   中英

哪些 C 规则允许在函数声明器中使用以前定义为类型的标识符?

[英]Which C rules allow to use in function declarator an identifier, which was previously defined as a type?

考虑这个代码(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

问题:

  1. 哪些 C 规则允许在函数声明器中使用以前定义为类型的标识符?
  2. 如果 msvc 说nonstandard extension ,那么为什么符合标准的 gcc / clang 什么也没说?

1

  1. 哪个 C 规则允许在函数声明器中使用以前定义为类型的标识符?

首先, typedef名称一个标识符。 C 2018 6.2.1 1 说:

标识符可以表示一个对象; 一个函数; 结构、联合或枚举的标记或成员; 一个 typedef 名称; 标签名称; 宏名称; 或宏参数...

同一个段落说我们可以使用相同的标识符来表示不同的实体:

…相同的标识符可以表示程序中不同点的不同实体…

第 4 段告诉我们在函数原型中声明的T隐藏了之前的T

… 在内部作用域内,标识符指定在内部作用域中声明的实体; 在外部作用域中声明的实体在内部作用域中隐藏(并且不可见)。

2

  1. 如果 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)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM