C语言中那些后知后觉的细节冷知识(二)typedef、死循环、位移、内存访问

系列文章目录

C语言中那些后知后觉的细节冷知识(一)static、const、volatile、数组、宏
C语言中那些后知后觉的细节冷知识(二)typedef、死循环、位移、内存访问
持续更新中… …


文章目录

  • 系列文章目录
  • 前言
  • 一、typedef
  • 二、死循环
  • 三、位移
  • 四、内存访问
  • 总结


前言

C语言诞生于1972年11月,由美国电话电报公司(AT&T)贝尔实验室的丹尼斯·里奇(Dennis Ritchie)发明,在1978年,美国电话电报公司(AT&T)贝尔实验室正式发布了C语言。C语言作为一种经典的编程语言,时至今日,仍然在许多领域仍然被广泛使用,并且仍然是一种强大、高效和灵活的编程语言。
学习C语言对于初学者来说可能有一定的难度,因为C语言是一种比较底层的编程语言,它提供了更接近计算机硬件的控制能力。与一些更高级的编程语言相比,C语言在语法和概念上可能更加复杂,需要更多的时间和精力来学习和掌握。
今天继续分享一些C语言的细节冷知识,主要涉及typedef、死循环、位移、直接内存访问等,希望对大家有所帮助。


一、typedef

在C语言中,typedef关键字用于为一个已经存在的类型创建一个新的名字。它通常用于帮助你简化代码、提高可读性,并为底层数据类型提供抽象。经常被用于为基本数据类型定义别名、为结构体定义别名、为枚举定义别名、为函数指针定义别名等。
与其比例类似的是宏定义#define,需要注意区别。比如以下例子:

#define dS struct s * 

typedef struct s * tS; 

以上两种情况的都是要定义dS 和 tS 作为一个指向结构s指针。哪种方法更好呢?答案是:typedef更好。思考下面的例子:

dS p1,p2;

tS p3,p4;

第一个例子在宏定义展开替换后为“Struct s * p1, p2;”,定义p1为一个指向结构体的指针,而p2为一个实际的结构。而第二个例子正确的定义了p3和p4两个指向结构体的指针。
所以一般在用于为一个已经存在的类型创建一个新的名字时,应尽量使用typedef,而不是#define。

二、死循环

死循环即无限循环,其实是普通的循环结构,但是没有退出循环的条件,即实现了无限循环。C语言中一般有以下几种方式实现死循环:
1、while(1){ … … }
2、for(;{ … … }
3、结合goto,如:
Loop:
… …
goto Loop;

推荐使用第一种while(1);如果使用第二种for(;,你也要了解为什么这样写for语句代表无限循环(其实就是第二个“;”语句中未填写退出for循环的条件造成的);第三种比较少用,可能经常写汇编语言的程序员会使用这种方式,但是不推荐。在C语言中,goto语句是一种控制流语句,允许程序无条件地跳转到程序中的另一个位置,但是很多的编码标准都谈及了避免或限制使用goto,主要原因是使用goto会降低代码的可读性、破坏程序的结构化、增加调试难度等。

三、位移

在C语言中,位移操作被广泛应用于各种场景,主要是由于其能够高效地操作二进制数据。位移操作通常比乘法和除法操作更快,因此在对性能有要求的计算场景中,可以使用位移来替代乘法和除法(左移N位相当于乘以2的N次幂,右移N位则相当于除以2的N次幂)。
在C语言中使用位移操作符(左移 << 和右移 >>)时,需要注意以下几点:
1、操作数的类型:位移操作符通常应用于整数类型(如short 、int、long等)的操作数。对浮点数应用位移操作符是未定义的行为(各位可以查一查浮点数在内存中的存储方式,就知道为什么了);
2、符号位:对于有符号整数,位移操作可能会涉及到符号位(最高位)。左移时,符号位会被“推出去”,并从另一端补入新的位(通常是0,但取决于具体的实现)。右移时,符号位的行为取决于编译器:算术右移(保留符号位)或逻辑右移(不保留符号位);
3、位移量:位移量应该是非负整数,并且小于或等于被操作数类型的位数。例如,对于32位整数,有效的位移量范围是0到31。超出这个范围的位移量可能导致未定义的行为。在实际编程中,通常会使用无符号类型(如 unsigned int)的变量来存储位移量,以避免负值;
4、无符号整数与有符号整数的区别:对于无符号整数,位移操作通常是逻辑移位,即左移时补0,右移时也补0。而对于有符号整数,右移可能是算术移位(保留符号位)。

四、内存访问

C语言主要运用于嵌入式系统中,而嵌入式系统经常会要求程序员去访问某特定的内存位置,主要的方式就是采用将绝对地址的整型数强制转换为指针,从而进行内存访问。比如:

int *ptr;
ptr = (int *)0x123456;
*ptr = 0xAABB;
//或者
*(int *)(0x123456) = 0xAABB;

上述代码可以实现对绝对地址为0x123456的内存赋值为0xAABB的目的。


总结

以上都是一些C语言的基础,但却又是平时编程中很容易因为疏忽出现问题的地方。更多的细节冷知识将在后续系列文章中持续更新,希望对大家有所帮助。

你可能感兴趣的:(C/C++,c语言,算法,开发语言,c++,单片机,嵌入式硬件,mcu)