C语言之关键字

本文总结自《C语言深度解剖》和网络博客。

C 语言标准定义的 32个关键字

auto 声明自动变量,缺省时编译器一般默认为 auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
float 声明浮点型变量
short 声明短整型变量
signed 声明有符号类型变量
unsigned 声明无符号类型变量
struct 声明结构体变量
union 声明联合数据类型
enum 声明枚举类型
static 声明静态变量
switch 用于开关语句
case 开关语句分支
default 开关语句中的“其他”分支
break 跳出当前循环
register 声明寄存器变量
const 声明只读变量
volatile 说明变量在程序执行中可被隐含地改变
typedef 用以给数据类型取别名(当然还有其他作用)
extern 声明变量是在其他文件正声明(也可以看做是引用变量)
return 子程序返回语句(可以带参数,也可不带参数)
void 声明函数无返回值或无参数,声明空类型指针
continue 结束当前循环,开始下一轮循环
do 循环语句的循环体
while 循环语句的循环条件
if 条件语句
else 条件语句否定分支(与 if 连用)
for 一种循环语句(可意会不可言传)
goto 无条件跳转语句
sizeof 计算对象所占内存空间大小

变量的定义和声明

定义:(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。
声明:告诉编译器,这个名字已经匹配到一块内存上了 ,这个名字先预定了,别的地方再也不能用它来作为变量名或对象名。
从变量的作用域来角度看,分为全局变量(函数外)、静态全局变量(文件作用域,函数外)、局部变量(函数内)
从变量值存在的时间(即生存期)角度来分,可以分为静态存储方式(全局数据区)和动态存储方式(栈stack)。
可见生存周期只是和变量存储的位置相关,所以auto、register、static、extern不能同时存在。

1. auto

auto变量,函数中的局部变量,如不专门声明为 static 存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。关键字 auto可以省略,auto 不写则隐含定为“自动存储类别”,属于动态存储方式。
)auto变量必须定义在函数体内,仅仅在函数内可见

2. register

register寄存器变量,请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内存寻址访问以提高效率。注意是尽可能,不是绝对。
1) 只有函数内局部变量或形式参数可以作为寄存器变量;
2) 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量;
3) 局部静态变量不能定义为寄存器变量
4) register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度。 而且 register 变量可能不存放在内存中, 所以不能用取址运算符“ &”来获取 register 变量的地址

3.extern

外部变量声明,是指这是一个已在别的地方定义过的对象,这里只是对变量的一次重复引用,不会产生新的变量。
extern“C”的用法 :
被extern “C”修饰的变量和函数是按照C语言方式编译和链接的
首先看看C++中对类似C的函数是怎样编译的。
作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void foo( int x, int y );
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字
详细信息参考:http://www.jianshu.com/p/5d2eeeb93590

4.static

4.1 修饰变量

静态全局变量
作用域:从定义之处开始,到文件结尾处结束 ;定义之前使用加extern,其他文件加extern也无法使用。
存储位置:静态存储方式(全局数据区)
静态局部变量
作用域:在函数体里面定义的,就只能在这个函数里用了,同一个文档中的其他函数也用不了。
存储位置:静态存储方式(全局数据区),函数运行结束后变量不会被销毁,下次调用函数时继续使用。

4.2 修饰函数

静态函数:static这里只对函数作用域进行说明(仅限于本文件),不是指存储方式

5. 基本数据类型:short int long char float double

基本数据类型

6. sizeof

sizeof是关键字而非函数,可以不加括号:

int i=0;
sizeof(int); //4
sizeof(i); //4
sizeof i; // 4        sizeof 在计算变量所占空间大小时,括号可以省略,
sizeof int; // error  而计算类型(模子)大小时不能省略.

几个例子:
32 位系统下:

sizeofint) *p  ==>  4*p
int *p = NULL;sizeof(p)的值是多少? ==> 4sizeof(*p)呢? ==> 4
int a[100]; 
sizeof (a) 的值是多少? ==> 表示数组总大小 400 = sizeof(int) * 100 
sizeof(a[100])呢? //请尤其注意本例。 ==> 同sizeof(int) = 4
sizeof(&a)呢? ==> 4
sizeof(&a[0])呢? ==> 4
int b[100];
void fun(int b[100])
{
sizeof(b);// sizeof (b) 的值是多少? ==> 4
}

7. signed unsigned

int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;}

答案:255
分析:-1的补码是0xff,-2的补码是0xfe;当i=127,a[127]=-128;a[128]=0x7f;a[255]=-256,-256的补码的低八位都是0,相当于‘\0’。

1)按照我们上面的解释,那-0 和+0 在内存里面分别怎么存储?没有区别,1000 0000代表-128
2) int i = -20;
unsigned j = 10;
i+j 的值为多少?为什么?
printf(“i+j=%d\n”,j+i); -10
printf(“i+j=%u\n”,j+i); 4294967286
unsigned int跟 signed int运算,会转换成unsigned int类型
3) 下面的代码有什么问题?
unsigned i ;
for (i=9;i>=0;i–)
{
printf(“%u\n”,i);
}
i是unsigned 类型,永远不会比0小

8.if else

bool变量与0值比较:if(boolFlag) if(!boolFlag)
float变量与0值比较:if((floatVal >= -EPSINON) && (floatVal <= EPSION))
指针变量与0值比较:if(NULL==p) if(NULL!=p)

9.switch case

switch后面支持byte short int long char,不支持bool float double
case后面只能是(整型/字符型)常量或常量表达式

10. void

void 真正发挥的作用在于:
(1) 对函数返回的限定;
(2) 对函数参数的限定。
void *可以指向任何类型的数据。
1) ANSI(American National Standards Institute)标准b不能对void指针进行算法操作
2)GNU(GNU’s Not Unix 的递归缩写)则不这么认定,它指定 void 的算法操作与 char 一致。
3)void 不能代表一个真实的变量

11. return

return 用来终止一个函数并返回其后面跟着的值。
return 语句不可返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁 .

12. const

常量永远无法改变,const只读变量一般无法直接再次赋值,但可通过指针改变。
const 是constant的缩写,是恒定不变的意思,也翻译为常量、常数等。 精确来讲const变量应该说是只读变量,其值在编译时不能被使用

const 修饰的只读变量必须在定义的同时初始化
编译器通常不为普通 const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高

#define M 3 //宏常量
const int N=5; //此时并未将 N 放入内存中
……
int i=N; //此时为 N 分配内存,以后不再分配!
int I=M; //预编译期间进行宏替换,分配内存
int j=N; //没有内存分配
int J=M; //再进行宏替换,又一次分配内存!

const 定义的只读变量从汇编的角度来看, 只是给出了对应的内存地址, 而不是象#define一样给出的是立即数,所以, const 定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。#define 宏是在预编译阶段进行替换,而 const 修饰的只读变量是在编译的时候确定其值。#define 宏没有类型,而 const 修饰的只读变量具有特定的类型。

“近水楼台先得月”
const int *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
int const *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
int *const p; //const 修饰 p, p 不可变, p 指向的对象可变
const int *const p; //前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象
都不可变

13. valatile

volatile 是易变的、不稳定的意思
volatile 关键字和 const一样是一种类型修饰符 ,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

const volatile int i=10;这行代码有没有问题?如果没有,那i到底是什么属性?
没问题,表明这个对象体现常量语义,但同时被当前对象所在程序上下文意外的情况修改(如:多线程),volatitle表示易变得,不会被编译器优化。每次都去内存中取值。

14. struct

14.1 空结构体多大

structstudent
{
}stu;
sizeof(stu)的值是多少呢?
答案:不是 0,而是 1。

14.2 柔性数组

柔性数组( flexible array)

typedef structst_type
{
    int i;
    int a[];
}type_a;

这样我们就可以定义一个可变长的结构体,用 sizeof(type_a)得到的只有 4,就是
sizeof(i)=sizeof(int)。那个 0 个元素的数组没有占用空间,而后我们可以进行变长操作了。通
过如下表达式给结构体分配内存:
type_a p = (type_a)malloc(sizeof(type_a)+100*sizeof(int));
再用 sizeof( *p)测试结构体的大小,发现仍然为 4。
在定义这个结构体的时候,模子的大小就已经确定不包含柔性数组的内存大小。柔性数组只是编外人员,不占结构体的编制。

14.3 struct 与 class 的区别

struct 的成员默认情况下属性是 public 的,而 class 成员却是 private 的。

15. union

在 union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所
有的数据成员具有相同的起始地址。
在 C++里, union 的成员默认属性页为 public。 union 主要用来压缩空间。

15.1 大小端模式对union类型数据的影响

union
{
int i;
char a[2];
}*p, u;
p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;

大端模式( Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放
在高地址中。
小端模式( Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放
在低地址中。
对 union 型的成员的存取都是相对于该联合体基地址的偏移量为 0 处开始,也就是联合体的访问不论对哪个变量的存取都是从 union 的首地址位置开始。

15.2 如何用程序确认当前系统的存储模式

请写一个 C 函数,若处理器是Big_endian 的,则返回 0;若是 Little_endian 的,则返回 1。

int checkSystem( )
{
union check
{
int i;
char ch;
} c;
c.i = 1;
return (c.ch ==1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值