C语言深度解剖 -- 关键字(一)

本文深入探讨了C语言中的关键字,包括定义与声明的区别、auto的默认作用、register提高效率的原理、static的多重含义,以及基本数据类型、sizeof的使用、signed和unsigned的特点、if和switch的条件判断,还有do-while、for循环的关键字应用。文章详细阐述了每个关键字的功能和注意事项,帮助读者更好地理解C语言的关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、定义和声明的区别

1、定义:(编译器)创建一个对象,为这个对象分配一块内存并给它取上一 个名字,这个名字就是我们常说的变量名或对象名。

2、声明:告诉编译器,这个名字(变量名或对象名)已经匹配到一块内 存上了,下面的代码用到变量或对象是在别的地方定义的。声明可以多次。告诉编译器,这个名字(变量名或对象名)已被预订,别的地方再也不能用它来作为变量名或对象名。

二、最宽宏大量的关键字——auto

1、auto : 在缺省的情况下,编译器默认所有变量都是auto的。

三、最快的关键字——register

1、register : 这个关键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率。CPU——寄存器——内存(寄存器相当于一个中转站,数据从内存里取,将变量存在CPU内存寄存器里,方便CPU直接取出数据,不需要从内存里再取了)

2、优点是:速度快

3、注意点:(1)register变量必须是能被CPU寄存器所接受的类型(必须是一个单个的值,并且长度应小于或等于整形的长度)
(2)register变量可能不存放在内存中,所以不能用取址“&”来获取register变量的地址

四、最名不符实的关键字——static

1、修饰变量:
(1)静态全局变量: 作用域仅限于变量被定义的文件中(从定义之处开始,到文件结尾处结束),定义之前的代码如果要使用,就要在前面加extern***。
(2)静态局部变量:在函数体里面定义的,就只能在这个函数里用了。由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束了,这个静态变量的值也不会被销毁,函数下次使用时任然能用到这个值。

2、修饰函数:
(1)函数前加static使得函数成为静态函数。但,static的含义是指对函数的作用域仅局限于本文件(又称内部函数)。使用内部函数的好处:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。

3、static的两种含义:a、表示退出一个块后仍然存在的局部变量。b、表示不能被其他文件访问的全局变量和函数。

五、基本数据类型

1、基本类型:
(1)数值类型:

	整型:短整型 short(2)、int(4)、long(4)
	浮点型:float(4)、double(8)

(2)字符类型:char(1)

2、构造类型:

数组、结构体struct、共用体union、枚举类型enum

3、指针类型
4、空类型void

5、变量的命名规则:

(1)一般规则:
规则1:命名应当直观且可以拼读,可忘文知意,便于记忆和阅读。
规则2:命名的长度应当符合“min ——length&&max——information”原则。
规则3:当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。
规则4:尽量避免名字中出现数字编号,除非逻辑上的确需要编号,
	   比如驱动开发时为引脚命名,非编号名字反而不好。
规则5:对在多个文件之间共同使用的全局变量或函数要加范围限定符。
(2)标识符的命名规则:
规则6:标识符名分为两部分:规范标识符前缀(后缀)+ 含义标识。
	  非全局变量可以不使用范围限定符前缀。
规则7:作用域前缀命名规则
规则8:数据类型前缀命名规则
规则9:含义标识命名规则,变量命名使用名词性词组,函数命名使用动词性词组
规则10:程序中不得出现仅靠大小写区分的相似的标识符。
规则11:一个函数名禁止被用于其他之处。
规则12:所用宏定义、枚举常量、只读变量全用大写字母命名,用下划线分割单词。
规则13:考虑到习惯性问题,局部变量中可采用通用的命名方式,
	   但仅限于n,i,j等作为循环变量使用。
规则14:定义变量的同时千万不要忘记初始化。
	   定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据。
规则15:不同类型数据之间的运算要注意精度扩展问题,
	   一般低精度数据将向高精度数据扩展。
六、最冤枉的关键字——sizeof

1、sizeof是关键字而不是函数(eg:int i;此时sizeof i 为4 )。
2、sizeof在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。
3、`

	sizeof(int) *p;  ——————???
	int *p = NULL;
	sizeof(p);
	sizeof(*p);`
	int a[100];
	sizeof(a);
	sizeof(a[100]);
	sizeof(&a);
	sizeof(&a[0]);
	
	int b[100];
	void fun(int b[100])
	{
		sizeof(b);
	}
七、signed、unsigned关键字

1、最高位为1,表明这个数是负数;最高位为0,表明这个数是正数。
2、在计算机系统中,数值一律用补码来表示(存储)。主要原因是:使用补码可以将符号位和其他位统一处理,同时,减法也可按加法来处理。
3、两个用补码表示的数 相加时,如果最高位(符号位)有进位,则进位被舍弃。
4、正数的补码与原码一致,负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。
5、strlen函数是计算字符串长度的,并不包含字符串后面的‘\0’。

八、if、else组合

1、bool变量和“零值”进行比较

bool bTestFlag = FALSE;
if(bTestFlag)
if(!bTestFlag)

2、float变量和“零值”进行比较

float fTestFlag = 0.0;
const float EPSINON = 0.000001;//是定义好的float类型的精度
if((fTestFlag >= -EPSINON)&&(fTestFlag <= EPSINON));

3、指针变量和“零值”进行比较

int *p = NULL;
if(NULL ==p);
if(NULL != p)

4、else始终与同一括号内最近的未匹配的 if 语句结合

5、if 的空语句建议写成

if (condition)
{
	NULL;
}

6、注意事项:
(1)先处理正常情况再处理异常情况
(2)确保if 和else 子句没有弄反

九、switch、case组合

1、用于分支很多的嵌套语句,这样可以提高效率。
2、每个 case 语句的结尾绝对不要忘记加 break ,否则将导致多个分支重叠。
3、最后必须使用 default 分支即使程序不需要 default 处理,也应该保留以下语句:

default :
	break;

4、case 后面只能是整型或字符型的常量或常量表达式。
5、case 语句的排列顺序:

规则1:按字母或数字顺序排列各条 case 语句。
规则2:把正常情况放在前面,而把异常情况放在后面。
规则3:按执行频率排列 case 语句。(最常执行的情况放在前面,
 而把不常执行的放在后面。)

6、其他注意事项:

规则1:简化每种情况对应的操作。
规则2:不要为了使用 case 语句而刻意制造一个变量。
规则3:将 default 子句只用于检查真正的默认情况。
十、do、while、for关键字

1、while(1) 表示死循环。
2、break 和 continue 的区别:
(1)break 表示终止本层循环。
(2)continue 表示终结本次(本轮)循环。(本轮循环结束, 进入下一轮循环)
3、while(1) || while(true) || while(1 == 1) || while((bool) 1) 这几种效果一样。

4、do-while 循环先执行do 后面的代码,再判断 while 后面括号里的值,如果为真,循环开始,否则,循环不开始。
5、for循环:for循环可以很容易的控制循环次数,多用于事先知道循环次数的情况下。

6、循环语句的注意点:
规则1:在多重循环中,如果有可能,应当将最长的代码放在最内层,
       最短的循环放在最外层,以减少 CPU 跨切循环层的次数。
       (长循环在最内层, 效率高。)
规则2:建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法。
规则3:不能在 for 循环体内修改循环变量,防止循环失控。
规则4:循环要尽可能地短,要使代码清晰,一目了然。
	  (循环体内的代码一般不超过 20 行)
规则5:把循环嵌套控制在 3 层以内。

7、禁止使用 goto 语句。

十一、void 关键字

1、void 的字面意思是 “空类型”, void * 则为“空指针”,可以指向任何类型的数据。
2、void 的作用:对函数返回的限定,对函数参数的限定。
3、void * ,任何类型的指针都可以赋值给他,无需进行强制类型转换(但 void * 不可以赋值给其他类型的指针,因为“空类型”可以包含“有类型”)

void *a;
int *b;
a = b;
// b = a;

4、void修饰函数返回值和参数

规则1:如果函数没有返回值,应将其声明为 void 类型(在C语言中,
		凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。)
规则2:如果函数无参数,那么应声明其参数为 void 。

5、void 指针

规则1:小心使用 void 指针类型, 不能对void *类型进行算法操作
规则2:如果函数的参数可以是任意类型指针,那么应声明其参数为void *。

6、void不能代表一个真实的变量,因为定义变量时需要分配内存空间,但定义void 类型变量时,编译器不知道该给这个变量分配多大的空间。

十二、return关键字

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

十三、const关键字

1、const 修饰的是只读的变量。

2、const 推出的最初目的是 取代预编译指令,消除它的缺点,同时继承它的优点。

3、const 和 define 宏的区别:

(1)const 修饰的只读变量必须在定义的同时初始化。
(2)编译器通常不为 const 只读变量分配存储空间,而是将他们保存在符号表中,使得他们成为一个编译期间的值,没有了存储和读内存的操作,使得他们的效率很高。(节省空间,避免不必要的内存分配,同时提高效率。)

(3)const 给出了对应的内存地址,#define给出的是立即数。
(4)const定义的只读变量在程序运行过程中只有一个备份(因为他是
     全局的只读变量,存放在静态区),#define 定义的 宏常量在内存
     中有若干备份。
(5)const 修饰的只读变量是在编译的时候确定其值,
     #define定义的宏常量在预编译阶段进行替换。
(6)const 修饰的只读变量具有特定的类型,#define 宏没有类型。

4、修饰一般变量

int const i = 2;  或 const  i = 2;

5、修饰数组

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

6、修饰指针

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

7、修饰函数的参数

void Fun(const int i)  // 告诉编译器 i 在函数体中不能改变     

8、修饰函数的返回值

const int Fun(void ) //返回值不可被改变
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值