欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

必知必会-C语言关键字篇

时间:2023-04-28
关键字 1.register

register:这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内存寻址访问以提高效率。注意是尽可能,不是绝对,因为一个CPU的寄存器的数量是有限的,不可能把这些变量都放入寄存器中。

寄存器:数据从内存里拿出来先放到寄存器,然后 CPU 再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU 不直接和内存打交道。

为啥要这么麻烦啊?因为速度。寄存器其实就是一块一块小的存储空间,只不过其存取速度要比内存快多。近水楼台先得月嘛,它离 CPU 很近,CPU 一伸手就拿到数据了,比在那么大的一块内存里去寻找某个地址上的数据快多了,同时寄存器的价格也比较高昂。

使用 register 修饰符的注意点

虽然寄存器的速度非常快,但是使用register 修饰符也有些限制的:register变量必须是能被 CPU 寄存器所接受的类型。意味着register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度。 而且 register变量可能不存放在内存中,所以不能用取址运算符“&”来获取register 变量的地址。

2.static

2.1修饰变量

变量又分为局部和全局变量,但它们都存在内存的静态区。

静态全局变量,作用域仅限于变量被定义的文件中,其他文件即使用extern 声明也没法使用他。准确地说作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些代码行也不能使用它。想要使用就得在前面再加extern XXX。静态局部变量,在函数体里面定义的,就只能在这个函数里用了,同一个文档中的其他函数也用不了。由于被 static 修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁,函数下次使用时仍然能用到这个值。

static int j;void fun1(void){static int i = 0; i ++;}void fun2(void){j = 0;j++;}int main(){for(k=0; k<10; k++){fun1();fun2();}return 0;} i 和 j 的值分别是什么,为什么?

2.2修饰函数

函数前加 static 使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

在一段程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区(静态区)中高地址分布着.bss段,低地址分布着.data段。总的分布如图所示。

全局区(静态区)
全局区有.bss段和.data段组成,可读可写。

.bss段

未初始化的全局变量存放在.bss段。初始化为0的全局变量和初始化为0的静态变量存放在.bss段。.bss段不占用可执行文件空间,其内容有操作系统初始化。

.data段

已经初始化的全局变量存放在.data段。静态变量存放在.data段。.data段占用可执行文件空间,其内容有程序初始化。const定义的全局变量存放在.rodata段。

3.sizeof

经常被误解为函数,sizeof是关键字不是函数。

int i=0;(A)sizeof(int);(B)sizeof(i); (C)sizeof int; (D)sizeof i;

思考一下:假设在 32 位系统下为什么A、B、D的结果为4,而C编译器提示出错呢.

4.signed与unsigned

一个 32 位的 signed int 类型整数其值表示法范围为:- 231~ 231 -1;8 位的char 类型数其值表示的范围为- 27 ~ 27 -1。一个 32 位的 unsigned int 类型整数其值表示法范围为:0~ 232 -1;8 位的 char 类型数其值表示的范围为 0~ 28 -1。

5.break 与 continue 的区别

break 关键字很重要,表示终止本层循环。现在这个例子只有一层循环,当代码执行到

break 时,循环便终止。

如果把 break 换成 continue会是什么样子呢?continue表示终止**本次(本轮)**循环。当

代码执行到 continue 时,本轮循环终止,进入下一轮循环。

6.cosnt 6.1修饰只读变量

定义 const 只读变量,具有不可变性。

例如:

const int Max=100;int Array[Max];

6.2节省空间

编译器通常不为普通 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 修饰的只读变量具有特定的类型。

6.3修饰一般变量

一般常量是指简单类型的只读变量。这种只读变量在定义时,修饰符 const 可以用在类型说明符前,也可以用在类型说明符后。例如:

int const i=6; const int i=6;

6.4修饰数组

定义或说明一个只读数组可采用如下格式:

int const a[3]={1, 2, 3};const int a[3]={1, 2, 3};

6.5修饰指针

const int *p; // p 可变,p 指向的对象不可变int const *p; // p 可变,p 指向的对象不可变int *const p; // p 不可变,p 指向的对象可变const int *const p; //指针 p 和 p 指向的对象都不可变

这里给出一个记忆和理解的方法:先忽略类型名(编译器解析的时候也是忽略类型名),我们看 const 离哪个近。“近水楼台先得月”,离谁近就修饰谁。

6.6修饰函数的参数

const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外改变时使用。例如:

void Fun(const int i);告诉编译器 i 在函数体中的不能改变,从而防止了使用者的一些无意的或错误的修改。

6.7修饰函数的返回值

const修饰符也可以修饰函数的返回值,返回值不可被改变。例如:

const int Fun (void);

7.volatile

volatile 是易变的、不稳定的意思。很多人根本就没见过这个关键字,不知道它的存在。也有很多程序员知道它的存在,但从来没用过它。

volatile 关键字和 const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问

volatile int i=10;int j = i;int k = i;

volatile关键字告诉编译器i是随时可能发生变化的,每次使用它的时候必须从内存中取出 i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k 中。

8.struct与union

相同点:二者都是常见的符合结构,都是由多个不同的数据类型成员组成;

不同点:联合体中所有的成员共用一块地址空间,即联合体只存放一个被选中的成员,内存空间是最长成员占用的空间,需要进行内存对齐。

​ 结构体所有成员占用空间是累加的,其所有成员都存在,不同成员会存在不同的地址,内存空间等于所有成员 占用的空间之和,同样需要内存对齐。

9.枚举与#define 宏的区别

#define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。一般在编译器里,可以调试枚举常量,但是不能调试宏常量。枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个 10.typedef

在实际项目中,为了方便,可能很多数据类型(尤其是结构体之类的自定义数据类型),需要我们重新取一个适用实际情况的别名。这时候 typedef 就可以帮助我们。例如:

typedef struct student{ //code}Stu_st,*Stu_pst;struct student stu1;和 Stu_st stu1;没有区别。struct student *stu2;和 Stu_pst stu2;和 Stu_st *stu2;没有区别。

推荐阅读:

面试中常被问到的C语言基础知识值得收藏 (qq.com)

参考书籍:

[1]C primer

[2]C 专家编程

[3]C陷阱与缺陷

[4]C和指针

感谢阅读:)

inner peace

知行合一

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。