作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
声明定义虽然无处不在,但是真正的想区分它们,却不是表面上那么简单。
首先,从广义的角度来讲声明中包含着定义:定义又可以称之为,“声明性定义”;而狭义的声明,有可称之为“引用性声明”。
下面,我们就来讨论“声明性定义”与“引用性声明”。的区别,之后简称定义与声明。
1、定义时系统会为定义的变量分配空间,而声明时,不会分配空间。这个是本质上的区别。
2、定义在程序中只能出现一次,而声明可以多次。比如:
如果两个c中有相同的全局变量“定义”,且没有初始化,编译器会认为第二个是声明而不是定义。
所以连续写两个int a;int a; 编译也不会出错,但是连续写int a = 1;int a = 1;编译出错。(函数也一样)
3、由2可见,在定义变量时初始化的副作用是告诉编译器,这是一个定义,而不是一个声明。因为声明时,是不可以
初始化的,具体的例子就是 extern int a; 这表示这是个声明而不是定义。如果写成extern int a = 1;编译就会报错。
结合1来想,这个就很正常了,因为声明是没有分配空间的,如何赋值呢?
4、定义时可以完成声明,并且初始化!例如 int a = 0; //定义,声明,初始化就包含这一条语句之中。
//--------关于extern的用法-------------------
extern的作用就是进行声明,实现调用其他文件的全局变量,或者函数。
由于声明可以多次,一般有的变量会被其他文件文件调用,那么一般会在该文件的头文件多声明一次改变量——extern + 变量。
那么如果另外一个文件包含了该头文件,就可以调用该变量。
//--------关于struct的声明定义初始化-------------------
1、struct的定义(这里注意的是,struct定义的是类型,而不是变量;但是以上结论同样适用!)
struct people //定义类型
{
char name[20];
int age;
};
2、struct people; //声明类型,同样写两句一模一样的不会错!但是类型定义也只能一次。
3、定义类型时,同时利用类型声明(定义)变量。这里类肯定是定义好了,而s1如果没有其他初始化代码,这里就是即声明又定义了。
struct student
{
char name[20];
int age;
}s1;
4、结构体变量的初始化,这个需要在3的前提下,这种形式的初始化可以不按照定义时的顺序,可帅气的称之为“乱序初始化”
struct student s1 =
{
.age = 10,
.name = "linux", //注意初始化结构体变量是用的是逗号,而定义结构体类型时,用的是分号。
};
5、省略掉类型的声明(定义)
struct
{
char name[20];
int age;
}s1;
但是无法像4中那样单独的初始化。
6、定义结构体类型时,无法初始化结构体变量,如下写法会报错:
struct student //错误写法
{
char name[20] = linux ;
int age = 10;
}s1;
7、于似乎再次发现一种神奇的写法:这样写也是有效的
struct student
{
char name[20];
int age;
}s1 =
{
.age = 10,
.name = "linux",
};
8、去掉类型名字,这样写也是有效的
struct
{
char name[20];
int age;
}s1 =
{
.age = 10,
.name = "linux",
};
定义结构体类型,同时定义结构体变量,并初始化变量,就是这么帅~~
9、struct {}a和 struct a{} 的区别
前者是定义了a(结构体)变量,后者是定义了结构体类型a。
//--------关于enum的声明定义初始化-------------------
这个就直接摘抄朱老师(朱有鹏)笔记吧。
/*
****************************************************************
* enumeration 类型定义
****************************************************************
*/
// 定义方法1,定义类型和定义变量分离开
enum week
{
SUN, // SUN = 0
MON, // MON = 1;
TUE,
WEN,
THU,
FRI,
SAT,
};
enum week today;
// 定义方法2,定义类型的同时定义变量
enum week
{
SUN, // SUN = 0
MON, // MON = 1;
TUE,
WEN,
THU,
FRI,
SAT,
}today,yesterday;
// 定义方法3,定义类型的同时定义变量
enum
{
SUN, // SUN = 0
MON, // MON = 1;
TUE,
WEN,
THU,
FRI,
SAT,
}today,yesterday;
// 定义方法4,用typedef定义枚举类型别名,并在后面使用别名进行变量定义
typedef enum week
{
SUN, // SUN = 0
MON, // MON = 1;
TUE,
WEN,
THU,
FRI,
SAT,
}week;
// 定义方法5,用typedef定义枚举类型别名,并在后面使用别名进行变量定义
typedef enum
{
SUN, // SUN = 0
MON, // MON = 1;
TUE,
WEN,
THU,
FRI,
SAT,
}week;
结构体,枚举,使用方法总结:
1、结构体,枚举使用有很多相似的地方;
2、定义枚举类型时,用的是分号。而且可以同时初始化其实的变量。
3、枚举类型不管是类型名还是,枚举内部的变量都是全局的,所以都不能重名。而结构体内部的变量是局部的。
4、使用枚举是可以直接用其中的变量如:SUN;而结构体需要这么访问:s1.age
最后是关于static的声明:
static来声明一个变量的作用有二个:
(1)对于局部变量用static声明,则是为该变量拥有全局变量的特性——在整个程序的执行期内都始终存在。因为他和全局变量一样在数据段。而不再栈上。
同时拥有局部变量的特性——无法被外部程序访问,这个就是生命周期的问题。
(2)全局变量或者是函数用static来声明,则起到“隐蔽”的作用——该变量的作用域只限于本文件。其他文件无法访问。
加上extern也不行。