C语言 数据类型修饰符与存储类修饰符

来源:互联网 发布:java实战项目案例 编辑:程序博客网 时间:2024/05/19 23:59

C语言允许修改简单数据类型的默认特征。这些数据类型修饰符主要改变允许的值的范围。

数据类型修饰符之应用于数据,而不针对函数。程序员可以在变量、参数和函数的返回值里使用它们。

某些数据类型修饰符能够同任何变量一起使用,而其他则只用于特殊类型的一个集合。

    数值常量修饰符:constvolatile

编译器优化程序的能力依赖于多个因素,其中之一是程序里数据对象的相对持久性。默认时,程序里使用的变量是根据开发者给出的指令改变数值的。

有时,程序员想创建不能改变数值的变量。例如,如果代码中用到了∏,即常数PI,则应该在一个常数变量里指定该数值的一个近似值。

const float PI=3.1415926;

当程序被编译后,编译器为PI变量分配ROM空间并且不允许在代码中改变它的数值。例如,下面的赋值将在编译时产生一个错误。

PI=3.0

在嵌入式C里,常量数据值的存储是从计算机程序的内部空间分配的,通常是ROM或者其他的非易失性存储体。

volatile变量是超出正执行软件范围其值就可能改变的变量。例如,一个“存储”在端口数据寄存器位置的变量将随着端口值的改变而改变。

使用volatile关键词通知编译器,它不能依赖于变量的值且不基于被赋予的值执行任何优化。

    允许值修饰符:signedunsigned

默认情况下,整数数据类型能够容纳负数值。可以限制整数数据类型只取正数值。整数数据类型的符号值是用signed(有符号)和unsigned(无符号)关键词来指定的。

Signed关键词迫使编译器使用整数值的高位作为符号位。如果符号位被设置为1,则变量的其余部分被解释为一个负数值。shortintlong数据类型默认为是有符号的,char数据类型默认为是无符号的。为了创建一个有符号的char变量,必须使用下面的声明:

signed char mysignedchar

如果单独使用signedunsigned关键词,编译器则假定正在声明一个整数值。因为int值是默认有符号的,所有程序员很少使用语法signed mysignedint;。

    大小修饰符:shortlong

修饰符shortlong指示编译器应为一个int变量分配多少空间。

short关键词修改int,使它同一个char变量具有相同大小的位(通常是8位)。

short int myshortint

入股单独使用short关键词,编译器会认为该变量是一个short int 类型。

short myshortint

long关键词修改int,使它同一个正常的int变量一样长。

long int mylongint

同样省略long声明后的int仍被认为是long int

④指针范围修饰符:nearfar

关键词nearfar深受目标计算机体系结构的影响。

Near关键词创建一个指向可寻址内存低端部分的目标的指针。这些指针占用内存的单一字节,并且它们能够指向的内存单元被限制到256个位置,通常是0x0000~0xffff的范围里。

int near * mynintptr

far关键词创建一个能够指向内存中任何数据的指针。

const char * mystring=constant string”;

char far * myindex=&mystring

这些指针需要两字节的内存,允许它们占据0x0000~0xffff之间的任何合法地址。Far指针通常指向用户ROM里的目标,如用户定义的函数和常量。

5.3.5 存储类修饰符

存储类修饰符控制已声明的修饰符的内存分配。C支持4种存储类修饰符,它们可以用于变量声明:extern,static,register,auto.只有extern用于函数声明。

当编译器读一个程序时,它必须确定如何为每个标识符分配存储空间。完成这个任务的过程被作连接。C支持3类连接:外部连接,内部连接和无连接。C使用标识符连接以分类对相同标识的多个引用。

1.外部连接

带有外部连接的标识引用在整个程序里调用内存中相同的目标。带有外部链接的标识的定义必须是唯一的,;否则,在编译器将给出一个重复符号定义的错误。默认情况下,程序中的每个函数都有外部链接。同样在默认情况下,全局范围的任何变量也都具有外部链接。

2.内部连接

在每个编译单元里,带有内部链接标识的所有引用指向内存中的相同目标。这就意味着,在程序的每个编译单元里,带有内部链接的标识的定义只能是惟一的。因为采用#include指令,一个编译单元能够多于一个文件。

默认情况下,C里没有目标具有内部链接。具有全局范围(定义在任何语句快外)并且具有static存储类修饰符的任何标识拥有内部链接。同样地,具有局部范围(定义在语句块里)并且具有static存储类修饰符的任何标识拥有内部链接。

尽管能够创建具有内部链接的局部变量,划分范围的规则把局部变量的可见性限制到它们的封闭语句块里。这意味着能够创建这样的局部变量,允许它们的值存在于它们所出现的语句块的即时生存期之外。正常情况下,计算机在多个不同的语句块间共享局部变量空间。如果一个局部变量被声明为static,则仅为该变量分配一次内存空间:发生在遇到变量的第一时间。

注意:不像其他内部链接目标,静态局部变量在编译单元里不必是独一无二的。它们必须在包含它们范围的语句块里是独一无二的。

内部链接的目标通常远远不如外部链接或者无链接的目标出现的频繁。

3.无链接

无链接标识的引用在语句块里指向内存中相同的目标。如果在一个语句块里定义了一个变量,则只能提供这种定义一次。

默认情况下,在一个语句块里声明的任何变量都是无链接的,除非ststic或者extern关键词被包含在声明中。

4.extern修饰符

extern修饰符指出该变量属于另一个模块或库。编译器可以访问该变量,当不给它分配空间。空间在定义它的那个文件中进行分配。为了是编译器知道该数据类型,必须利用extern声明。

当编译器遇到一个外部函数声明时,就将它解释为有函数名、类型和参数的一个函数原型。关键词extern宣告函数定义位于另一个编译单元。编译器把解析这个引用的任务推给链接器。

如果建立了一个应用于许多程序的函数库,并创建了一个包含extern函数声明的头文件。那么,在编译单元里包括这个头文件,以便程序员自己的代码可以得到函数库里的函数。

如同函数一样,全局变量也有外部链接。全局变量是一个展现函数库的通用配置设置的好方法。这样可以避免额外的函数调用。

为建立一个在编译单元外部可读或可设置的全局变量,必须在它的源文件里正常声明它,并在一个头文件里用extern声明它。

编译器解释一个外部声明为一个通知;实际的RAMROM分配发生在另一个编译单元里。

5.static修饰符

默认情况下,在全局空间里声明的所有函数和变量具有外部链接并且对整个程序是可见的。有时需要具有内部链接的全局变量或者函数:它们应该在一个单一的编译单元里是可见的,但在外部则不可见。使用static关键词限制变量的范围。

当它用于某函数块内部时,static修饰符促使编译器创建一个持久性存储数据。所以该数据在此函数外部是持久的。若没有使用static修饰符,该变量可能是自动的变量,它使用栈空间。

在函数内部使用static修饰符通常被认为不是好的编程习惯。在主调例程中,程序员应当首先考虑是使用全局变量还是自动变量会更好些。在协同多任务程序中,通常static修饰符用得较多。但要注意:可能会造成非可重入的 函数。

6.register修饰符

当使用register修饰符时,编译器便试图将CPU寄存器分配给数据。但若该寄存器必须用于其他操作,则数据就转到栈上临时存储。此类修饰符能够减少程序尺寸与执行时间,但它仅对于较简单程序有效。

不像其他存储类修饰符,register只是给编译器一个简单的建议。如果没用用于分配的寄存器,则编译器可能使用正常内存空间。

因为在8位机器上寄存器的匮乏以及空间优化胜过速度,所以对嵌入式程序员而言,register关键词没有太大的用处。

7.auto修饰符

关键词auto指示一个临时变量(与static相反)。C在一个语句块内部都不支持函数,所以auto只能用于局部变量。既然默认情况下在以语句块里声明的所以变量是无链接的,那么使用auto关键词的惟一理由是提供代码清晰度。

8.volatile修饰符

volatile修饰符用于指出当其他某种异步事件发生时数据内容会发生改变。结果,它告诉编译器,该数据无任何持久性。异步事件包括外部硬件事件、中断驱动事件,以及在可抢占性多任务系统中从别的任务来的任务间事件。易失性数据对象的最普通的例子是通用输入或通用I/O端口数据。它迫使编译器每次需要此数据内容时都必须读该单元,而不是只读一次数据并将它放在寄存器中以便后续访问之用、从而使程序优化。

9.const修饰符

该修饰符用于声明存储常量。它促使编译器将常量值存入ROM中所分配的空间。当是使用const修饰符时,必须将数据对象初始化。如果程序员试图改变存储常量的值,编译器便会给出出错信息。这个修饰符很少用在通用计算机应用程序中,因为它的一切数据对象都存放在RAM中。

原创粉丝点击