我是C的新手,我在声明和变量定义之间遇到了一些混淆。另一件我想知道的是,如果以下情况属实:
“宣言多次出现,定义一次。”
此外:
int x;
这只是一个声明吗?由于内存是为x
分配的,那为什么这不是一个定义而不是一个声明?
答案 0 :(得分:8)
只需在全局范围或本地范围内编写int x;
,都一个声明和定义。通常,声明告诉编译器“此变量将在某个时候以此名称存在,因此您可以使用它”。该定义告诉编译器实际安排要创建的变量 - 显然这只能发生一次。
通常,您使用此方法的方法是输入一个标题文件:
// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined
extern int bar; // Declare a variable bar
#endif
并在单个源文件中
#include "foo.h"
int bar; // Define bar
如果要在多个文件中定义条形,则会出现错误;你不能两次创建变量。但是你必须在你使用bar
的每个源文件中告诉编译器它。因此extern
声明。
精确语义在C标准的第6.9.2节中定义,可归纳如下:
static
存储类说明符的文件范围内声明变量,则它是暂定定义。如果翻译单元(文件)具有一个或多个暂定定义且没有外部定义,则编译器会自动在翻译单元的末尾添加真正的文件范围声明,零初始化器。 (§6.9.2/ 2)这意味着,严格来说,int x;
不是定义;但它会自动创建一个定义当且仅当没有初始化程序的其他定义,并且没有static
定义时(由于链接不一致,第三种情况是未定义的行为,根据§6.2.2 / 7)
请注意,extern int x;
不是外部定义。它是一个带有extern
存储类说明符的声明。因此,仅extern int x;
不会导致创建定义,但如果同时具有两者:
extern int x;
int x;
然后,您将最终在文件中的某个位置创建定义。
从技术上讲,这也是合法的:
extern int x;
int x;
int x = 42;
在这种情况下,中间的int x;
是多余的,没有任何效果。也就是说,这是一种糟糕的形式,因为在这种情况下实际定义是令人困惑的。
答案 1 :(得分:7)
这不是你在C中看得太多的东西,但它的工作原理如下:
在头文件中,您可以使用以下行:
extern int x; //declaration
由于extern
修饰符,这告诉编译器有一个名为x 的int 。编译器不为它分配空间 - 它只是将int x
添加到您可以使用的变量列表中。当它看到像这样的一行时,它只会为x
分配空间:
int x; //definition
您可以看到,因为只有int x;
行更改了您的可执行文件,您可以拥有尽可能多的extern int x;
行。只要只有int x;
行,一切都会像你想要的那样工作 - 多个声明不会改变一件事。
一个更好的例子来自C ++(对不起,如果这是一个只有C的问题 - 这也适用于struct
s,但我不知道我的头脑中的语法:/ p>
class Pineapple; //declaration
Pineapple* ptr; //this works
Pineapple pine; //this DOES NOT work
此声明告诉编译器有一个名为“Pineapple”的类。它没有告诉我们关于班级的任何信息(它有多大,它的成员是什么)。我们现在可以使用指向Pineapples的指针,但是我们还没有实例 - 我们不知道菠萝的构成是什么,所以我们不知道实例需要多少空间。
class Pineapple
{
public:
int ounces;
char* name;
}; //definition
Pineapple* ptr; //still works
Pineapple pine; //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;
在定义之后,我们知道关于类的所有内容,因此我们也可以拥有实例。和C示例一样,您可以有多个声明,但只有一个定义。
希望这有帮助!