C中变量的声明和定义之间的混淆

Ami*_*mar 4 c variables

我是C的新手,我在变量的声明和定义之间经历了一些混淆.我想知道的另一件事是如果以下情况属实:

"宣言多次出现,定义一次."

也:

int x; 
Run Code Online (Sandbox Code Playgroud)

这只是一个声明吗?既然分配了内存,x为什么这不是一个定义而不是声明?

bdo*_*lan 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
Run Code Online (Sandbox Code Playgroud)

而在一个单一的源文件

#include "foo.h"
int bar; // Define bar
Run Code Online (Sandbox Code Playgroud)

如果要在多个文件中定义条形,则会出现错误; 你不能两次创建变量.但是你必须在你使用的每个源文件中告诉编译器它bar.因此extern声明.

精确语义在C标准的第6.9.2节中定义,可归纳如下:

  • 当使用初始化程序在文件范围声明变量时,它是外部定义.(§6.9.2/ 1)
  • 如果在没有初始化程序的情况下在文件范围内声明变量,并且没有存储类说明符或static存储类说明符,则它是一个暂定的定义.如果转换单元(文件)具有一个或多个暂定定义而没有外部定义,则编译器会自动在转换单元的末尾添加一个真正的文件范围声明,并使用零初始值设定项.(§6.9.2/ 2)

这意味着严格来说,int x;这不是一个定义; 但它会自动创建定义当且仅当没有其它定义与一个初始化,并没有static定义(这第三种情况是不确定的行为由于每§6.2.2/ 7联动分歧)

请注意,这extern int x;不是外部定义.它是一个带有extern存储类说明符的声明.因此,extern int x;单独不会导致创建定义,但如果您同时具有:

extern int x;
int x;
Run Code Online (Sandbox Code Playgroud)

然后,您将最终在文件中的某个位置创建定义.

从技术上讲,这也是合法的:

extern int x;
int x;
int x = 42;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,int x;中间是多余的,没有效果.也就是说,这是一种糟糕的形式,因为在这种情况下实际定义是令人困惑的.


Xav*_*olt 7

这不是你在C中看得太多的东西,但它的工作原理如下:

在头文件中,您可以使用如下行:

extern int x; //declaration
Run Code Online (Sandbox Code Playgroud)

由于extern修饰符,这告诉编译器在某处有一个名为x的int .编译器不为它分配空间 - 它只是添加int x到您可以使用的变量列表中.它只会x在看到如下所示的行时分配空间:

int x; //definition
Run Code Online (Sandbox Code Playgroud)

您可以看到,因为只有int x;行更改了您的可执行文件,您可以拥有尽可能多的extern int x;行.只要只有int x;一条线,一切都会像你想要的那样工作 - 多个声明不会改变一件事.

一个更好的例子来自C++(对不起,如果这是一个只有C的问题 - 这也适用于structs,但我不知道我头脑中的语法):

class Pineapple; //declaration

Pineapple* ptr;  //this works
Pineapple pine;  //this DOES NOT work
Run Code Online (Sandbox Code Playgroud)

声明告诉编译器有一个名为"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;
Run Code Online (Sandbox Code Playgroud)

定义之后,我们知道关于类的所有内容,因此我们也可以拥有实例.和C示例一样,您可以有多个声明,但只有一个定义.

希望这可以帮助!