1

C89, 4.1.2 标准标题(已添加重点):

保留以下划线开头的所有外部标识符。

C99(及更高版本),7.1.3 保留标识符,1(强调添加):

所有以下划线开头的标识符始终保留用作普通和标记名称空间中具有文件范围的标识符。

C 的基本原理,7.1.3 保留标识符,25(强调添加):

同样为实现者保留的是以下划线开头的所有外部标识符,以及以下划线开头的所有其他标识符,后跟大写字母或下划线。

因此,根据 C99(及更高版本),在:

typedef int _t;        // non-reserved in C89, reserved in C99 (and later)
static int _f(int x);  // non-reserved in C89, reserved in C99 (and later)

(在文件范围内声明)_tand_f是保留的,这与 Rationale 和 C89 相矛盾。

这是否意味着 C99(及更高版本)在 7.1.3 保留标识符中遗漏了“外部”:“所有外部标识符……”?

UPD。桌子:

                                is _x reserved ?

                                C89     C99 (and later)
scope - linkage
function - external             n/a     n/a
function - internal             n/a     n/a
function - none                 no      no
file - external                 yes     yes**
file - internal                 no      yes**
file - none                     no      yes**
block - external                yes     no*
block - internal                n/a     n/a
block - none                    no      no
function prototype - external   n/a     n/a
function prototype - internal   n/a     n/a
function prototype - none       no      no

其中*是一个可能的缺陷,见下文,并且**是“在普通和标记名称空间中”(C11,7.1.3 保留标识符,1)。

在这里,我们看到 C99(及更高版本)保留更多(如果表格正确)。额外:为了什么目的?

4

2 回答 2

2

C99(及更高版本)7.1.3 保留标识符是否缺少“外部”?

显然 C99 和 C 的每个后续版本,直到并包括当前最新的 C17,在您询问的条款中省略了“外部”的限定。这并不一定构成他们文本中的缺陷。

因此,根据 C99(及更高版本),在:

typedef int _t;        // non-reserved in C89, reserved in C99 (and later)
static int _f(int x);  // non-reserved in C89, reserved in C99 (and later)

(在文件范围内声明)_tand_f是保留的,这与 Rationale 和 C89 相矛盾。

是的,那些出现在文件范围内的声明分别声明_t_f没有链接和内部链接。它们不是外部标识符(尽管它们是在外部声明中声明的),因此 C89 不保留它们用于该用途。另一方面,C99 及更高版本保留它们以供该用途使用。

“矛盾”对于这种差异来说太强烈了。是的,C99 保留了一些 C89 没有的标识符用法(反之亦然)。这不是两者之间唯一的向后不兼容。C99“取消并替换”C89,因此前者不需要与后者的所有细节保持一致。

至于理由,是的,它解释了保留的 C89 版本,而不是 C99 形式。我认为是基本原理的一个缺陷,毕竟这不是规范的。

这是否意味着 C99(及更高版本)在 7.1.3 保留标识符中遗漏了“外部”:“所有外部标识符……”?

我认为没有理由得出结论,在 C99 及以后的该条款中省略“外部”代表编辑错误。事实上,我将周围文本的相应更改作为更改是故意的证据。特别是,C89 文本继续使用“所有其他以下划线和大写字母或另一个下划线开头的标识符”(添加了强调),而 C99 及更高版本也删除了“其他”。据我所知,C99 打算保留比 C89 更多的标识符使用。

但是这里有一个可能的缺陷,即 C89 保留了一些 C99 没有但可能打算这样做的标识符使用。这些是块范围内的外部标识符,以下划线开头,不紧跟大写字母或另一个下划线。例子:

int f(void) {
    extern int _var;
    extern int _func(int);

    // ...
}

_var和的这些用法_func在 C89 中保留,但在 C99 及更高版本中不保留。符合标准的 C 代码无法提供链接到这些标识符的定义,因为所有版本的规范中的标识符保留都不允许这样做,但它们可能与实现定义的外部标识符发生冲突。

于 2022-02-23T03:17:21.497 回答
0

我认为 C89 和 C99 中的规则是相同的(即保留您的示例用法),但措辞已得到改进。释义:

  • 旧:“保留外部标识符 [描述]”。
  • 新增内容:“标识符 [描述] 保留用于外部声明”。

该标准甚至没有定义术语“外部标识符”;或许这是改变措辞的动机之一。

如果我们将“外部标识符”理解为“由外部声明声明的标识符”,那么规则是相同的。


注:外部声明是指“具有文件范围的声明”(C11 6.9/4);这通常与“声明带有外部链接的标识符”相混淆。

C89 标准确实使用了特定文本“具有外部链接的标识符”(例如 A.6.3.2),所以我不认为“外部标识符”应该是指“具有外部链接的标识符”。

于 2022-02-23T01:36:09.927 回答