其他类型关键字

1.const 关键字

const关键字声明一个变量是“只读”的,在C语言中这意味这这个变量的值不能改变。所以,我在这里只说是“只读”的变量,而没有用“常量”这个容易引起混淆的说法。

例:int const a = 20;

/*下面这个声明有语法错误,因为a是一个变量,在编译的时候变量a的值是不确定的*/

int array[a];

如果一个变量的值是只读的,那么被const关键字修饰的变量的值如何获得?

两种情况:

1)在声明“只读”变量的时候,对这个变量赋初值,如 int const a = 20;

2)如果const关键字被用于修饰函数的形参,在函数调用的时候会得到实参的值。

const int a;

int const a;

const int *a;

int * const a;

int const * const a;

第一行和第二行的含义是一样的,都是声明整数变量a是只读的,你可以选择你认为比较好的理解的方式进行编写。

第三行声明一个指向整数的指针变量a,这个指针的值是可以改变的,但是这个指针所指向的整数值(*a)是不可以改变的。

第四行是声明一个指向整数的指针变量a,这个指针的值是只读的,但是这个指针所指向的整数值(*a)是可以改变的。

第五行声明一个指针变量a,不管这个指针变量的值还是指针变量所指向的整数值都是只读的,是不可改变的。

const关键字存在的意义:

1)为给读代码的人传达非常有用的信息,实际上声明一个参数为常量是为了告诉用户这个参数的应用目的。

2)通过给编译器一些附加的信息,使用关键字const也许能产生更紧凑的代码。比如,很多嵌入式微处理器在处理const关键字修饰的变量时,往外会将这些变量的地址分配给ROM的地址空间(比如68000的编译器会专门有一个数据段被称为const段,被声明为const的变量都会被分配到这个段中)

3)合理使用const可以使编译器很自然的保护那些不希望被改变的参数,防止其被无意的代码修改。

const关键字作用:

欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会改变它了。

对指针来说可以指定指针本身为const,也可以指定指针所指的数据为const,或者二者同时指定为const。

 

2. sizeof关键字

sizeof是C语言中的关键字,同时也是一个操作符,它的作用就是返回一个对象或者类型所占的内存字节数,它的3种使用形式,如下:

sizeof(var); /*sizeof(变量);*/

sizeof(type_name);   /*sizeof(类型);*/

sizeof var;    /*sizeof(变量)*/

数组的sizeof值等于数组所占用的内存字节数:

char* ss = "0123456789";

sizeof(ss);    /*结果4,ss是指向字符串常量的字符指针*/

sizeof(*ss); /*结果1,*ss是第一个字符*/

char ss[] = "0123456789"; 

sizeof(ss); /*结果11, 计算到‘\0’位置,因此是10+1*/

sizeof(*ss); /*结果1,*ss是第一个字符*/

char ss[100] = "0123456789";

sizeof(ss);            /*结果100,表示在内存中的大小100*1*/

strlen(ss);   /*结果10,strlen是到'\0'为止之前的长度*/

int ss[100] = "0123456789";

sizeof(ss);  /*结果400,ss表示在内存中大小100*4*/

strlen(ss);   /*错误,strlen的参数只能是char*且必须以‘\0’结尾*/

 

3. typedef 关键字

C语言支持通过typedef关键字定义新的数据类型,typedef声明的写法与普通的声明基本相同,只需要把typedef关键字写在前面,

例:typedef char *ptr_to_char这个声明把标识符ptr_to_char作为指向char类型的指针类型的新名字。

此后,程序员可以像声明其他变量一样用这个新名字来声明一个char类型的指针变量,比如:ptr_to_char a;的含义是声明一个指向char类型的指针变量a。

 使用typedef来定义自己的新数据类型有3个好处:第一,使用typedef定义类型可以避免使声明变的非常长;第二,如果需要在以后修改程序中所使用的一些数据的类型时,只需要修改一个typedef声明就可以了,比在程序中一个变量,一个变量的修改更容易,而且也避免漏掉某个变量声明的风险;第三,对于需要在不同处理器直接进行代码移植,通过typedef可增加代码的可移植性。例:

typedef usigned short U16;

typedef unsgined int U32;

/*如果移植到int为16位的机器,则只须修改这个定义即可,如下面的定义*/

//typedef unsigned long U32;

typedf void *   P_VOID;

typedef struct message_body

{

  U16 messageType;

  U16 message;

  U32 Iparam;

  P_VOID data;

  U16 wparam;

  U16 reserved;

} MSG, *PMSG;

PMSG MessagePtr;                          /*定义一个指向消息结构的指针*/

MessagePtr = (PMSG)malloc(sizeof(MSG));    /*申请一块内存空间用来存放消息*/

/*如果不用上面的方式,就得采用下面的方法申请存储器*/

/*显然采用以下方式,语句的长度会变的很长,程序的可读性变差*/

//MessagePtr = (struct message_body *)malloc(sizeof(struct message_body));

注:好的变差风格推荐程序员使用typedef关键字而不是#define宏来定义新的数据类型,这其中一个原因是#define宏无法正确地处理指针类型。

例:#define d_ptr_to_char char *

d_ptr_to_char a,b;

正确地声明了变量a为一个指向char类型的指针变量,但是变量b却被声明为一个char类型的整数。在定义更为复杂的类型(比如函数指针活指向数组的指针)时,使用typedef关键字更为合适。

4.volatile 关键字

一个定义为volatile的变量可能会被意想不到的改变,这样编译器就不会去假设这个变量的值。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:

1)并行设备的硬件寄存器(如状态寄存器);

2)一个中断服务子程序中会访问到的非自动变量(non-automatic variables);

3)多线程应用中被几个任务共享的变量。

几个问题:

1)一个参数既可以是const也可以是volatile吗?

答:是的。一个例子是只读的状态寄存器,它是volatile,因为它可能被意想不到地改变。它是const,因为程序不应该试图去修改它。

2)一个指针可以是volatile吗?

答:是的,尽管这并不很常见。例如当一个中断服务子程序修改一个指向buffer的指针时。

3)下面的函数有什么错误:

int square(volatile int *ptr)

{

return *ptr **ptr;

}

答:这段代码有个恶作剧,这段代码的目的是用来返指针ptr指向值的平方,但由于ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr)

{

int a,b;

a = *ptr;

b = *ptr;

return a*b;

}

由于ptr的值可能会被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!正确的代码如下:

long square(volatile int *ptr)

{

int a;

a = *ptr;

return a*a;

}

posted @ 2020-12-09 16:33  抠脚女汉子思密达  阅读(172)  评论(0编辑  收藏  举报