提问人:Luchian Grigore 提问时间:5/12/2013 更新时间:9/3/2014 访问量:215
“外部声明或定义”不是我所想的吗?
Does "external declaration or definition" not mean what I think?
问:
17.6.2.2 标头 [using.headers]
3) 翻译单元只能在任何 外部声明或定义,并应包括标题 在该翻译单元中的第一个引用之前,在词汇上对任何 在该标头中声明的实体。
如果我的解释是正确的:
extern "C"
{
#include "smth.h"
}
是非法的(而且那里有很多)。
我是不是误读了?“外部声明”和“外部定义”是否意味着其他含义(在这种情况下)?
答:
标头在标准中定义为声明或定义 C++ 标准库元素的位置。这不包括用户的文件。参见 §17.6.1.2:.h
C++ 标准库的每个元素都在标头中声明或定义(根据需要)。
C++ 标准库提供了 52 个 C++ 库头文件,如表 14 所示。
C 标准库的功能以 26 个附加标头提供,如表 15 所示。
所以你给出的例子很好(只要文件本身不包含一些标准的库头文件)。但是,这不会是:.h
extern "C"
{
#include <string>
}
为了进一步备份标头和源文件(包括文件)之间的分离,预处理指令被定义为在语法中包含“标头”,并在语法中包含“源文件”(§16.2)。所以你包含的是源文件,而不是头文件。源文件被定义为程序的文本,它与它所包含的标题一起构成了一个翻译单元:.h
#include
<h-char-sequence>
"q-char-sequence"
#include "smth.h"
在本国际标准中,程序的文本以称为源文件的单位保存。源文件以及通过预处理指令包含的所有标头 (17.6.1.2) 和源文件 (16.2),减去任何条件包含 (16.1) 预处理指令跳过的任何源行,称为翻译单元。
#include
我认为这种措辞的目的是将标准库标头与其表示方式分离。没有理由必须将它们存储为 C++ 源文件,即使它们通常是。包含特定的标头只需要具有向程序提供适当声明的效果。
评论
#include
我认为约瑟夫·曼斯菲尔德(Joseph Mansfield)的回答基本上正确地解释了“头”一词(它仅指§17.6.1.2 [头文件]中定义的标准库头文件),但我认为它还包括附录D中描述的C头文件,因为脚注176(在N3936中)将两者称为“标准头文件”。这个答案侧重于短语外部声明或定义的含义。<iso646.h>
<ciso646>
C++标准中的这个特定句子似乎是从C标准借来的。C89 标准中似乎存在相同的措辞,至少根据这个非官方版本,并且存在于 C99 和 C11 中。
虽然 C++ 标准没有定义“外部声明或定义”,但这些术语在 C 标准中定义(引用 N1256 §6.9):
预处理后的程序文本单位为翻译单位, 它由一系列外部声明组成。这些是 被描述为“外部”,因为它们出现在任何函数之外(并且 因此具有文件范围)。[...]
外部定义是一个外部声明,它也是一个 函数或对象的定义。
翻译单元的 C 语法是:
translation-unit:
external-declaration
translation-unit external-declaration
external-declaration:
function-definition
declaration
现在,C++标准中翻译单元的相应描述是 (§3.5 [basic.link]):
翻译单元由一系列声明组成。
语法很简单
translation-unit:
declaration-seq_opt
简而言之,在 C 中,翻译单元是一系列外部声明,而在 C++ 中,它是一系列声明。因此,C++ 标准中的“外部”一词似乎是由借用引起的历史产物,引用的句子旨在禁止在任何类型的声明或定义中包含标准库头。
评论
smth.h
extern "C"