gpt4 book ai didi

C - 在什么情况下外部声明成为定义?

转载 作者:行者123 更新时间:2023-12-02 01:50:46 27 4
gpt4 key购买 nike

来自 C99 标准 6.2.3:

If the declaration of an identifier of an object has file scope and no storage-class specifier, its linkage is external.

和6.7

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;99)
— for an enumeration constant or typedef name, is the (only) declaration of the identifier.

不幸的是,我还没有找到任何关于编译器何时将外部声明视为定义(这意味着类型必须完整并且存储大小已计算)的进一步描述。

所以我做了一些实验。首先我注意到:

struct A a;
int main() {
}

无效,gcc 说类型 A 不完整,它不知道如何为 a 分配存储空间。然而,有趣的是,我们有以下有效代码:

struct A a;
int main() {
}
struct A {int x;};

这也是合理的,因为类型 A 在文件末尾完成。从上面的两个例子,我们可以推断出外部声明是在文件范围的末尾检查的。 (仍然不知道标准在哪里说的)

但是,数组声明是异常(exception)的。修改后的代码不再有效:

struct A a[1];
int main() {
}
struct A {int x;};

C99 标准确实谈到了这一点,它说数组的元素必须是完整的类型。那么问题来了:struct A a[1] 是定义还是声明?不要急于回答。检查以下示例。

这里我们有两个文件:a.cb.c。在 a.c 中:

#include <stdio.h>
int arr[10];
void a_arr_info() {
printf("%lu at %lx\n", sizeof arr, (size_t)arr);
}

b.c 中:

#include <stdio.h>
int arr[20];
void b_arr_info() {
printf("%lu at %lx\n", sizeof arr, (size_t)arr);
}
int main() {
a_arr_info();
b_arr_info();
}

结果令人震惊。输出显示两个文件中的 arr 指的是同一个地址。这可以理解,因为 arr 都在文件范围内,因此它们是外部链接。问题是,它们的大小不同。编译器在哪个文件中将声明作为定义并分配内存?

我为什么要问这个?因为,嗯,我正在研究一个简化的 C 编译器项目(类(class)作业)。所以弄清楚它对我来说可能很重要。虽然作业没有到这一步,但我很好奇,想了解更多。谢谢!

最佳答案

这叫做暂定

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

所以任何具有这种暂定定义的编译单元(.o文件)都实现了该对象。将两个这样的单元链接在一起具有未定义的行为,您通常会遇到“多重定义符号”错误。一些编译器/链接器只是这样做,你必须确保这些符号具有相同的大小和类型。

关于C - 在什么情况下外部声明成为定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22928879/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com