Definition(定义) and Declaration(声明)

本文详细阐述了C语言中的定义(Definition)与声明(Declaration)的区别与联系,重点介绍了两者在实体Object操作中的作用,并通过具体实例展示了外部变量及结构体的定义与声明过程。

要弄懂这两者,没啥困难。可是,至少有半数以上的C书没能分清。有的书在某一章节里把这个问题说清楚了,可在其它章节里却乱说一气。真是无奈。

这两者都是对实体Object的操作。

对于任何一个实体,Definition必须有一次,也只能有一次。Declaration可以有0次,也可以有任意次。

Definition是真正产生实体,即为其分配存储空间。Declaration并不产生实体,事实上,被Declaration的实体必须是已经存在的。

譬如在源文件A里定义了一个外部的(即在任一函数外面的)整数数组:

       int   iArray[100];

编译器为其分配了400Bytes(如果你用的是32位编译器,每个整数占4Bytes)的空间。

如果你希望另一个源文件B里也能访问这个数组,你必须在文件B的头部对其做外部声明:

       extern     int    iArray[];

这是C专家编程里给出的例子。这例子举得好。你可能已经注意到声明里少了100。书里说得很明白:由于并未在声明中为数组分配内存,所以并不需要提供关于数组长度的信息。

这问题太简单了。你只需记住:对每个实体,定义数必须是1,声明数是0-N。如果你的代码不是这样,那就有Bugs。或者出错不能运行,或者得到的不是你预想的结果。

我以为,从结构化观点看,extern声明无非是把该数组的作用域从文件A扩展到文件B而已。

还有一种声明更为常见,就是结构、联合等的声明。与上述的不一样。许多书里说的是结构、联合的定义,我说的是声明。仍然是C专家编程里的例子。

struct      veg { int weight, price_per_lb; };

struct      veg onion, radish, turnip;

第一句声明了一个名为veg的结构类型,里面含两个int型成员。第二句定义了三个veg类型的结构变量。

我说是声明,按上面的说法,是不分配空间。在这里,这么说,恐怕会有点问题。不分配空间,也就是说,第一个语句不编译出任何代码。对于上面的两个语句,这样说能解释得通。但是,如果我在声明了结构类型后,想动态而不是静态生成结构变量,那在运行时如何按这不存在的东西去生成实体呢?

我没看过含结构类型声明的源代码编译后的目的码,不知道里面有没有与结构类型声明相关的代码。我猜想,这段代码是肯定有的。只是它不是用来运行的,而是用来复制的。你可以把它叫做模板,用来生成实体的模板。运行代码和模板代码可能放在不同的地方。

这个仅仅是猜想而已。曾几次把这猜想写在BBS上,很可惜,没人反对。因为没人反对,也就没法得到验证。

可以把结构类型的声明和结构变量的定义写在一起:

struct      veg { int weight, price_per_lb; } onion, radish, turnip;

在这种格式中,类型veg可以省略。但是不省略的好处是,你可以在以后再按veg定义第四、第五个结构变量。

       C专家编程里说得很好,结构类型的声明和结构变量的定义,还是分开写好。
<think>首先,用户的问题是关于C++中全局变量声明定义的位置。他们提到了几个引用,我需要参考这些引用来构建回答。 用户引用的内容: - 引用[1]:讨论了C++全局变量的声明定义。提到可以把声明定义放在一起以防止忘记定义,并使用extern进行引用。 - 引用[2]:解释了static修饰的全局变量是文件作用域的,在其他文件中使用时会有不同的内存地址。 - 引用[3]:描述了C语言中全局变量的定义声明,内存分配在bss段或data段。 用户的具体查询是:“我想查找全局变量声明定义的位置”,意思是“I want to find the location of declaration and definition of global variables”。 系统指令要求: - 使用LaTeX格式:行内数学表达式用$...$,独立公式用$$...$$。 - LaTeX语法正确。 - 中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,例如[^1]。 - 回答结构清晰,逐步解决问题,尽量真实可靠。 所以,我需要构建一个结构清晰的回答: 1. **解释声明定义的概念**:确保区分清楚。 2. **位置说明**:基于引用,讨论在哪里声明定义全局变量。 3. **最佳实践**:建议如何放置声明定义。 4. **添加引用标识**:在相关部分末尾添加引用。 5. **生成相关问题**:在回答末尾添加相关问题。 关键点来自引用: - **声明**:告诉编译器变量的类型和名称,但不分配内存。通常在头文件中。 - **定义**:实际分配内存并可能初始化变量。通常在源文件中。 - 引用[1]建议将声明定义放在一起使用extern,以防止错误。 - 引用[2]讨论了static全局变量的作用域。 - 引用[3]解释了内存分配细节。 步骤: 1. **介绍概念**: - 声明Declaration):指定变量类型和名称,但不分配内存。示例:`extern int globalVar;` - 定义Definition):分配内存并可能初始化。示例:`int globalVar = 10;` 2. **位置**: - **声明**:通常放在头文件(.h)中,以便多个源文件访问。 - **定义**:放在源文件(.cpp)中,以避免多重定义错误。 - 对于static全局变量:定义在源文件中,作用域仅限于该文件(引用[2])。 - 避免在头文件中定义变量,除非使用extern或static适当。 3. **最佳实践**: - 在头文件中声明变量为extern,例如:`extern int globalVar;` - 在源文件中定义它,例如:`int globalVar = 0;` - 引用[1]提到可以将声明定义放在一起,但那可能不是标准做法。 4. **内存分配**: - 引用[3]:全局变量定义时分配内存在bss或data段。 5. **结构回答**: - 使用标题或编号使结构清晰。 - 例如: - 什么是声明定义? - 在哪里放置声明? - 在哪里放置定义? - 注意事项(如static)。 6. **添加引用**: - 在解释末尾自然地添加[^1]、[^2]等。 7. **生成相关问题**: - 在末尾添加§§相关问题§§部分。 8. **LaTeX使用**: - 如果有数学表达式,如讨论指针或内存地址,但这里可能不需要。确保如果有,使用正确格式。 - 例如,如果提到地址,用$address$。 最终回答: - 引言:解释用户查询。 - 主体:逐步解释。 - 结论:总结。 - 相关问题。 相关问题想法: 1. 如何避免全局变量的多重定义错误? 2. static全局变量与其他全局变量有什么区别? 3. 全局变量的初始化顺序问题? 4. C++中全局常量如何声明定义? 5. 为什么建议少用全局变量? </think>### 全局变量声明定义的位置 在C++中,全局变量的声明declaration)和定义definition)是编程中的关键概念,它们的位置直接影响代码的可维护性和编译正确性。下面我将基于您的引用内容,逐步解释如何在代码中正确放置全局变量的声明定义,确保结构清晰、真实可靠。声明用于告知编译器变量的存在和类型(不分配内存),而定义则为变量分配实际内存并可能初始化[^3]。 #### 1. **声明的位置:通常在头文件中** - 全局变量的声明应放在头文件(例如 `.h` 或 `.hpp`)中,以便在多个源文件中共享。声明使用 `extern` 关键字来表示变量在其他地方定义。 - 示例:在头文件 `globals.h` 中: ```cpp extern int globalVar; // 声明全局变量,extern 表示定义在其他位置 ``` - 这样,任何源文件包含该头文件(如 `#include "globals.h"`)时,就能访问该变量,而无需重复定义。这种方式防止了多重定义错误(multiple definition error),因为声明本身不分配内存[^1][^3]。 - **优点**:确保一致性,方便多文件项目管理。引用[1]提到,如果忘记定义编译器会报错,因此声明在头文件中是可靠的做法。 #### 2. **定义的位置:在源文件中** - 全局变量的定义必须放在源文件(例如 `.cpp`)中,且只能在一个源文件中定义一次。定义会分配实际内存地址(如BSS段或DATA段),并可能指定初始值。 - 示例:在源文件 `globals.cpp` 中: ```cpp int globalVar = 10; // 定义全局变量,分配内存并初始化 ``` - 编译器根据初始化值决定内存位置:初值为零时分配到BSS段(初始化为零),非零时分配到DATA段(拷贝初值)。这确保了变量在程序生命周期内持续存在[^3]。 - **注意事项**: - 避免在头文件中定义变量:如果在头文件中定义无 `extern` 的变量(如 `int globalVar;`),多个源文件包含该头文件会导致多重定义错误(linker error)。 - 使用 `static` 修饰符:如果将全局变量定义为 `static`(如 `static int fileLocalVar = 5;`),它只在当前源文件内部可用(文件作用域)。其他文件使用时,编译器会创建独立副本,内存地址不同,修改不影响原值[^2]。 #### 3. **最佳实践:声明定义分离** - **推荐结构**: - 头文件(e.g., `globals.h`):只包含 `extern` 声明。 - 源文件(e.g., `globals.cpp`):包含实际定义。 - 其他源文件(e.g., `main.cpp`):通过 `#include "globals.h"` 访问变量。 - 引用[1]建议将声明定义放在一起(如 `extern char g_szBuffer[];` 在头文件中),但这可能导致混淆。标准做法是分离声明定义,以提高模块性和可读性。如果担心忘记定义,可以结合Makefile或构建工具检查。 - **内存分配细节**:全局变量的定义在编译时分配内存,链接阶段解析地址引用。未初始化的全局变量自动初始化为零(BSS段),减少代码体积[^3]。 #### 总结 全局变量的声明放在头文件中(使用 `extern`),定义放在一个源文件中(分配内存)。这种分离方式确保了代码的健壮性和可复用性。对于 `static` 全局变量,定义在源文件中可实现文件级封装。实践中,建议尽量减少全局变量使用,优先考虑局部作用域或命名空间以减少副作用。 如果您有具体代码场景,我可以提供更针对性的建议!
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值