赞
踩
(A)int i;
(B)extern int i;
那个是定义?那个是声明?
什么是定义?(A)
- 所谓定义就是(编译器)创建一对象,为这个对象分配一块内存并给它起一个名字,这个名字就是我们经常说的变量名或对象名
- 一个变量或对象在一定区域内(比如函数内、全局等)只能被定义一次,如果被定义多次,编译器会提示你重复定义同一个变量或对象。
什么是声明?(B)
- 第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,下面用到的变量或对象是在别的地方定义的。声明可以出现多次。
- 第二重含义:告诉编译器,这个名字已经被使用了,别的地方不能用它作为变量名或对象名。
记住:定义和申明最重要的区别是:定义创建了对象并为这个对象分配了内存,声明没有分配内存。
C中的关键字extern是用来做变量声明的, 声明extern关键字的全局变量和全局函数可以使得它们的作用域得到扩展
在C中, 如果全局变量不在文件开头定义, 其有效作用范围(作用域)只限于全局变量定义处到文件结束, 在定义处之前不能使用该变量 ,如需在定义处之前想用该全局变量的话, 需要在用之前用extern对该变量进行外部变量声明, 表示将此变量的作用域扩展到此位置, 这样就合法了
一个C程序可以由一个或多个源文件组成, 如果由多个组成, 那么在想在一个文件用另一个文件中定义的全局变量怎么办呢?
- 如果在两个文件中都定义名字相同的变量, 会在连接时出现重复定义的错误, 正确的做法是, 在任意一个文件中在全局变量前加上extern修饰, 这样实际只定义了一个全局变量, 只是将其作用域扩展到了其他文件。
在text1.c中用extern声明的text2.c中变量a,则text1.c和text2.c中的a是地址相同的同一个变量,所以无论在
text1还是text2中改变a, a的值都会a发生改变
在声明函数时, 在函数最左端加关键字extern, 此函数就成为了外部函数, 可供其他文件调用(与之对应的是内部函数, 用staic修饰, 文章下面再来看)
注意: 在用static声明变量时, 只能在声明变量的基础上加static修饰, 而不能单独使用, 例如 下面用法不对
int a;
static a;
在C中和static类似不能这样用的关键字还有auto ,register
static修饰的变量只在当前文件可见,不同文件staic 修饰相同名字的变量时,变量的地址是不同的
static修饰的变量是不会放在符号表的,是不会给其他文件使用的
static修饰全局变量改变的是全局变量的作用域, 使全局变量只能在本文件中使用
运行结果出错, 可以看到static确实把a的作用域限定到了test.c中
static修饰局部变量, 会将局部变量存储在静态区(全局区)(普通局部变量存储在栈区), 改变局部变量的生命周期, 使其伴随整个程序, 程序运行结束时才会被释放
注意 : 虽然static修饰的局部变量改变了生命周期, 使其伴随整个程序, 程序结束前为其分配的空间一直都在, 但作用域并未改变
在声明函数时在其最左边加static修饰, 这个函数就成了内部函数, 内部函数又称为静态函数, 会使函数作用域只限定于本文件., 这样在不同文件中就算有相同名字的函数也不会相互干扰
通常一个大的程序往往由多人分工来编写不同的文件模块, 在不同人编写代码时,很可能会出现相同名字的函数, 此时, 在自己写的函数前加static修饰, 就不会出现函数重名的问题了, 这就保证了程序的可靠性.
#define是预处理指令,在编译时不进行任何检查,只进行简单的替换.
typedef是给一个存在的数据类型(注意:是类型不是变量)去一个别名,而非定义一个新的数据类型。
(1)#define之后不带分号,typedef之后带分号。
(2)#define可以使用其他类型说明符对宏类型名进行扩展,而 typedef 不能这样做。如:
#define INT32 int
unsigned INT32 n; //没问题
typedef int INT32;
unsigned INT32 n; //有问题
(3)在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。如:
#define PINT1 int*;
P_INT1 p1,p2; //即int *p1,p2;
typedet int* PINT2;
P_INT2 p1,p2; //p1、p2 类型相同
PINT1定义的p1与p2类型不同,即p1为指向整形的指针变量,p2为整形变量;PINT2定义的p1与p2类型相同,即都是指向 int 类型的指针。
(4)typedef 和 const 放在一起容易出现的错误
typedef struct student
{
//code
}Stu,*pStu;
(A) struct student s1; 和 Stu s1; 没有区别
(B) struct student* s2; 和 Stu* s2; 和 pStu s2; 没有区别
(C)const pStu s3;
(D)pStu const s4;
可能有的人会认为(C)中const 修饰的是s3指向的对象。(D)中const修饰s4这个指针。
很遗憾(C)中const修饰的是s3这个指针,因为 pStu 是 " struct student{ //code } *"的别名。
" struct student{ //code } *"是一个整体,对于编译器来说,只认为 pStu 是一个类型名,
所以在解析的时候很自然的把 "pStu"这个数据类型忽略掉。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。