为什么C语言中一个变量不能在2个文件中定义两次
为什么我不能在 2 个 C 文件中包含 int a; 。我打算将两者结合起来以使其可执行。 我从经验中知道我不能,但我想找到标准 C99 的位置并确定我的理解。
我正在阅读 http://www.ISO C99 标准。 open-std.org/jtc1/sc22/wg...docs/n1256.pdf。第42页写道:
6.2.2 标识符的链接
1 以不同方式声明的标识符 范围或在同一范围内超过 一次可以指代相同的 进程调用的对象或函数 联动有3种 链接:外部、内部和无。
2 在翻译单元集中并且 构成一个完整的库 程序中,每个声明 与外部的特定标识符 链接表示同一对象或 功能。在一个翻译单元内, 每个标识符的声明 内部链接表示相同 对象或函数。每份声明 没有链接的标识符 表示一个独特的实体。
3 如果声明一个文件范围 对象或函数的标识符 包含存储类说明符 静态,标识符有内部 链接。
4 对于使用以下声明的标识符 存储类说明符 extern 在 事先声明的范围 该标识符是可见的,如果先验的 声明指定内部或 外部链接,内部链接 稍后声明中的标识符是 与指定的链接相同 事先声明。如果没有事先 声明是可见的,或者如果 事先声明没有指定任何联系, 那么标识符有外部 链接。
5 如果声明一个标识符 对于没有存储类的函数 具体而言,其联系已确定 就好像它是用声明的一样 存储类说明符 extern.If 一个标识符的声明 对象具有文件范围并且没有 存储类说明符,其链接是 外部。
读完这篇文章后,看起来如果我在 2 个源文件中声明一个像 int a; 这样的变量。然后根据规则 5 和 4 都有外部链接。然后根据规则 2,两者都应该引用同一个对象。那么为什么编译器会产生问题呢?标准中暗示我们不能在两个源文件中这样声明,这应该会引发编译错误。首先,在标准中,它说 int a 是一个定义,然后它说 2 个定义实例是不可接受的。我知道根据我的经验这是不允许的,但如果我能在标准中找到这一点并密封我的理解,这对我来说非常有用。
以下标准摘录组合起来是否相当于本规则?或者我错过了胶水?:
声明指定 集合的解释和属性 标识符。的定义 标识符是一个声明 标识符:——对于一个对象,导致 为此预留的存储空间 目的; ——对于一个函数,包括 函数体; ——用于枚举 常量或 typedef 名称,是 (仅)标识符的声明。
如 5.1.1.1 中所述,单位 预处理后的程序文本是 翻译单元,它由一个 外部声明的顺序。 这些被描述为“外部” 因为它们出现在任何函数之外 (因此具有文件范围)。作为 6.7 中讨论了一个声明 还导致存储被保留 由 命名的对象或函数 标识符是一个定义。
外部定义是一个外部声明,也是一个定义 函数的(内联函数除外) 定义)或一个对象。如果一个 使用外部声明的标识符 链接用于表达式中 (除了作为操作数的一部分 sizeof 运算符,其结果是 整数常量),位于 整个程序应准确无误 一个外部定义 标识符;否则,应有 不超过一个。
谢谢。
Why can't I have int a; in 2 C files. I intend to combine both to make executable.
I know from experience that I can't, but I want to find where the standard C99 says this and seal my understanding.
I am reading ISO C99 standard from http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf. It says on page 42:
6.2.2 Linkages of identifiers
1 An identifier declared in different
scopes or in the same scope more than
once can be made to refer to the same
object or function by a process called
linkage.There are three kinds of
linkage: external, internal, and none.2 In the set of translation units and
libraries that constitutes an entire
program, each declaration of a
particular identifier with external
linkage denotes the same object or
function. Within one translation unit,
each declaration of an identifier with
internal linkage denotes the same
object or function. Each declaration
of an identifier with no linkage
denotes a unique entity.3 If the declaration of a file scope
identifier for an object or a function
contains the storage-class specifier
static,the identifier has internal
linkage.4 For an identifier declared with the
storage-class specifier extern in a
scope in which a prior declaration of
that identifier is visible,if the prior
declaration specifies internal or
external linkage, the linkage of the
identifier at the later declaration is
the same as the linkage specified at
the prior declaration. If no prior
declaration is visible, or if the
prior declaration specifies no linkage,
then the identifier has external
linkage.5 If the declaration of an identifier
for a function has no storage-class
specifier,its linkage is determined
exactly as if it were declared with
the storage-class specifier extern.If
the declaration of an identifier for an
object has file scope and no
storage-class specifier, its linkage is
external.
After reading this it looks that if I declare a variable like say int a; in 2 source files. then both have external linkage as per rule 5 and 4. and then as per rule 2, both should refer to the same object. Then why does the compiler create problem. Where in the standard it is hinted that we can't declare like this in 2 source files and this should throw compilation error. Firstly, where in the standard, it says that int a is a definition, and then where it says that 2 instances of definitions are not acceptable. I know that it is not allowed from my experience, but it would be very useful to me, if I can find this in the standard and seal my understanding.
Do the following excerpts from the standard in combination amount to this rule? or I have missed that glue? :
A declaration specifies the
interpretation and attributes of a set
of identifiers. A definition of an
identifier is a declaration for that
identifier that: —for an object, causes
storage to be reserved for that
object; —for a function, includes the
function body; —for an enumeration
constant or typedef name, is the
(only) declaration of the identifier.As discussed in 5.1.1.1, the unit of
program text after preprocessing is a
translation unit, which consists of a
sequence of external declarations.
These are described as ‘‘external’’
because theyappear outside anyfunction
(and hence have file scope). As
discussed in 6.7, a declaration that
also causes storage to be reserved for
an object or a function named by the
identifier is a definition.An external definition is an external declaration that is also a definition
of a function (other than an inline
definition) or an object. If an
identifier declared with external
linkage is used in an expression
(other than as part of the operand of
a sizeof operator whose result is an
integer constant), somewhere in the
entire program there shall be exactly
one external definition for the
identifier; otherwise, there shall be
no more than one.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为你需要 6.9.2/2:
和 6.9/5:
基本上,
int a;
是一个暂定定义。您可以在一个翻译单元中拥有多个暂定定义,但效果与拥有一个非暂定外部定义相同(例如,int a = 0;
)。在程序中对具有外部链接的对象进行多于一个的定义就违反了 6.9/5。请注意,它是一种“通用扩展”,允许一个对象有多个外部定义,只要最多只有一个被初始化并且定义一致(参见 J.5.11)。
I think you need 6.9.2/2:
and 6.9/5:
Basically,
int a;
is a tentative definition. You can have multiple tentative definitions in a single translation unit but the effect is the same as having one non-tentative external definition (e.g. something likeint a = 0;
). Having more that one definition of an object with external linkage in a program is a violation of 6.9/5.Note that it is a "common extension" to allow more than one external definitions of an object so long as at most only one is initialized and the definitions agree (see J.5.11).