C语言不可不用的关键字

来源:互联网 发布:virtualbox装centos 编辑:程序博客网 时间:2024/06/05 08:46
1.static关键字
要对static关键字深入了解,首先需要掌握标准C程序的组成。
标准C程序一直由下列部分组成:
1)正文段—CPU执行的机器指令部分,也就是你的程序。一个程序只有一个副本;只读,这是为了防止程序由于意外事故而修改自身指令;
2)初始化数据段(数据段)—在程序中所有赋了初值的全局变量,存放在这里。
3)非初始化数据段(bss段)—在程序中没有初始化的全局变量;内核将此段初始化为0。
注意:只有全局变量被分配到数据段中。
4)栈—增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。
5)堆——动态存储分配。
static在嵌入式C语言当中,它有三个作用:
作用一:在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
作用二:在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
作用三:在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
auto、register、extern和static
对应两种存储期:自动存储期和静态存储期。
auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。
关键字extern和static用来说明具有静态存储期的变量和函数。
用static声明的局部变量具有静态存储持续期(staticstorage duration),或静态范围(staticextent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。
2.const 关键字
合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。
a.const关键字修饰的变量可以认为有只读属性,但它绝不与常量划等号。如下代码:

const int i=5;
int j=0;
i=j;//非法,导致编译错误,因为只能被读
j=i; //合法

b.const关键字修饰的变量在声明时必须进行初始化。如下代码:
const int i=5; //合法
const intj;//非法,导致编译错误
c.用const声明的变量虽然增加了分配空间,但是可以保证类型安全。const最初是从C++变化得来的,它可以替代define来定义常量。在旧版本(标准前)的c中,如果想建立一个常量,必须使用预处理器:
#define PI 3.14159
此后无论在何处使用PI,都会被预处理器以3.14159替代。编译器不对PI进行类型检查,也就是说可以不受限制的建立宏并用它来替代值,如果使用不慎,很可能由预处理引入错误,这些错误往往很难发现。而且,我们也不能得到PI的地址(即不能向PI传递指针和引用)。
const的出现,比较好的解决了上述问题。
d.C标准中,const定义的常量是全局的。
e.必须明白下面语句的含义,我自己是反复记忆了许久才记住,方法是:若是想定义一个只读属性的指针,那么关键字const要放到‘*’后面。
char *const cp;//指针不可改变,但指向的内容可以改变
char const *pc1;//指针可以改变,但指向的内容不能改变
const char *pc2;//同上(后两个声明是等同的)
f.将函数传入参数声明为const,以指明使用这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值。参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。例子:
void fun0(const int * a);
void fun1(const int &a);
调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为constint * a,则不能对传递进来的指针所指向的内容进行改变,保护了原指针所指向的内容;如形参为constint & a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
g.修饰函数返回值,可以阻止用户修改返回值。(在嵌入式C中一般不用,主要用于C++)
h.const消除了预处理器的值替代的不良影响,并且提供了良好的类型检查形式和安全性,在可能的地方尽可能的使用const对我们的编程有很大的帮助,前提是:你对const有了足够的理解。
最后,举两个常用的标准C库函数声明,它们都是使用const的典范。
(1).字符串拷贝函数:char*strcpy(char *strDest,const char *strSrc);
(2).返回字符串长度函数:intstrlen(const char *str);
3. volatile关键字
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这变量的值,而不是使用保存在寄存器里的备份。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。
一般说来,volatile用在如下的几个地方:
(1)、中断服务程序中修改的供其它程序检测的变量需要加volatile;
(2)、多任务环境下各任务间共享的标志应该加volatile;
(3)、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;
不懂得volatile的内容将会带来灾难,这也是区分C语言和嵌入式C语言程序员的一个关键因素。为强调volatile的重要性,再次举例分析:
代码一:

int a,b,c;
//读取I/O空间0x100端口的内容
a= inword(0x100);
b=a;
a=inword(0x100);
c=a;

代码二:

volatile int a;
int a,b,c;
//读取I/O空间0x100端口的内容
a= inword(0x100);
b=a;
a=inword(0x100)
c=a;

在上述例子中,代码会被绝大多数编译器优化为如下代码:

a=inword(0x100)
b=a;
c=a;

这显然与编写者的目的不相符,会出现I/O空间0x100端口漏读现象,若是增加volatile,像代码二所示的那样,优化器将不会优化掉任何代码.从上面来看,volatile关键字是会降低编译器优化力度的,但它保证了程序的正确性,所以在适合的地方使用关键字volatile是件考验编程功底的事情.

4.struct与typedef关键字
面对一个人的大型C/C++程序时,只看其对struct的使用情况我们就可以对其编写者的编程经验进行评估。因为一个大型的C/C++程序,势必要涉及一些(甚至大量)进行数据组合的结构体,这些结构体可以将原本意义属于一个整体的数据组合在一起。从某种程度上来说,会不会用struct,怎样用struct是区别一个开发人员是否具备丰富开发经历的标志。在网络协议、通信控制、嵌入式系统的C/C++编程中,我们经常要传送的不是简单的字节流(char型数组),而是多种数据组合起来的一个整体,其表现形式是一个结构体。经验不足的开发人员往往将所有需要传送的内容依顺序保存在char型数组中,通过指针偏移的方法传送网络报文等信息。这样做编程复杂,易出错,而且一旦控制方式及通信协议有所变化,程序就要进行非常细致的修改。

用法:在C中定义一个结构体类型要用typedef:

typedef struct Student
{
int a;
}Stu;
于是在声明变量的时候就可:Stustu1;
如果没有typedef就必须用structStudent stu1;来声明这里的Stu实际上就是structStudent的别名。
另外这里也可以不写Student(于是也不能structStudent stu1;了)

typedef struct
{
int a;

Stu;
struct关键字的一个重要作用是它可以实现对数据的封装,有一点点类似与C++的对象,可以将一些分散的特性对象化,这在编写某些复杂程序时提供很大的方便性.
原创粉丝点击