《C专家编程》读书笔记8

第八章  为什么程序员无法分清万圣节和圣诞节

 

8.1       Portsebie度量衡系统

8.2       根据位模式构筑图形

8.3       在等待时类型发生了变化

       printf(“%d”, sizeof ‘A’);

       输出的结果是4(或者是你机器上int的长度)。字符常量的类型是int,根据提升规则,它由char转换为int。

 

       这个特性被称为类型提升。当它发生于整型类型时称为“整型提升”。

 

       char c1, c2;

       /* … */

       c1 = c1 + c2;

       “整型提升”规则要求把每个变量的值提升为int的长度,然后对两个int值执行加法运算,然后再对运算结果进行裁剪。如果两个char的加法运算结果不会发生溢出异常,那么在实际执行时只需要产生char类型的运算结果,可以省略类型提升。

 

       float f1, f2;

       double d;

       /* … */

       f1 = f2 * d;

       如果编译器可以确定用float进行运算的结果跟转换为double后进行运算的结果一样,那么可以使用float来进行乘法运算。

 

       整型提升就是char、short int和位段类型(无论signed或unsigned)以及枚举类型将被提升为int,前提是int能够完整地容纳原先的数据,否则将被转换为unsigned int。ANSI C表示如果编译器能够保证运算结果一致,也可以省略类型提升——这通常出现在表达式中存在常量操作数的时候。

 

       真正值得注意之处——参数也会被提升。

       这就是为什么单个的printf()格式符字串%d能适用于几种不同的类型,short、char或int,而不论实际传递的是上述类型的哪一个,函数从堆栈中(或寄存器中)取出的参数总是int类型。

 

       C语言中的类型转换不仅用于操作数上,使操作符两端数据类型一致,同时也提升比规范类型int或double更小的数据类型(即使它们类型匹配)。

 

8.4       原型之痛

      

       在K&R C中,如果向函数传递一个短语int的整数,函数实际所接收到的是int,如果传递的是一个float,函数实际接收到的是double。在被调用函数的函数体内,这些值会根据函数定义时参数的声明类型自动裁剪为该类型。

       如果适用了函数原型,缺省参数提升就不会发生。如果参数声明为char,则实际所传递的也是char。

 

8.5       原型在什么地方会失败

       如果未一个K&R C函数定义增加函数原型,而原型的参数列表中有一个short参数,在参数传递是,这个原型将导致实际传递给原型的就是short类型的参数,而根据函数的定义,它期望接收的是一个int类型的参数。这样,函数从堆栈中抓取4个字节(int)而不是2个字节(short)。

 

       文件1

       /*旧风格的函数定义,但它却具有原型*/

       olddef(d, i) float d; char i; {

           printf(“olddef: float = %f, char = %x \n “, d, i);

       }

       /*新风格的函数定义,但它却没有原型*/

       newdef(float d, char i) {

           printf(“newdef: float = %f, char = %x \n “, d, i);

       }

       文件2

       /*旧风格的函数定义,但它却具有原型*/

       int olddef ( float d, char i);

       main() {

           float d=10.0;

           char j = 3;

           olddef(d, j);

       /*新风格的函数定义,但它却没有原型*/

           newdef( d, j);

       }

       实际输出结果:

       olddef: float = 524288.000000, char = 4

       newdef: float = 2.562500, char = 0

       如果把函数的定义放在它们被调用的同一个文件内,也就是文件2,程序的行为就会不一样。编译器将会检测到olddef()的不匹配,因为它现在可以同时看到原型和K&R C的函数定义。如果把newdef()的定义放在它之前,编译器就会平静地执行正确的操作,因为此时函数的定义相当于原型,它保证了声明和定义的一致性。

 

8.6       不需要按回车键就能得到一个字符

8.7       用C语言实现有限状态机

 

       在C语言中,有好几种方法可以用来表示FSM,但它们绝大多数都是基于函数指针数组。一个函数指针数组可以像下面这样声明:

       void ( *state[ MAX_STATES])();

       如果知道了函数名,就可以像下面这样对数组进行初始化。

       extern int a(), b(), c(), d();

       int ( *state[])() = {a, b, c, d};

       可以通过数组中的指针来调用函数:

       ( *state[i])()

 

8.8       软件比硬件更困难

8.9       如何进行强制类型转换,为何要进行类型强制转换

8.10    轻松一下——国际C语言混乱代码大赛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值