依赖编程内部知识的C语言习惯用法
1.关于位图的自描述能力 图标或者图形是一种小型的位模式映射于屏幕产生的图像, 实际上,其实就是用原本十六进制表示的位图数组,表示为二进制方式分解方式。例如: 0x07c6,二进制就是0000022222000110,即oxo7c6 = (((((((((((((((((0) * 2 + 0) * 2 + 0) * 2 + 0) * 2 + 0) * 2 + 0) * 2 + 1)* 2 + 1)* 2 + 1)* 2 + 1)* 2 + 1)* 2 + 0)* 2 + 0)* 2 + 0)* 2 + 1)* 2 + 1)* 2 + 0) 我们进行如下宏定义: #define X )*2+1 则0x07c6实际表示为:s _ _ _ _ _ X X X X X _ _ _ X X _ 通过这种方式,可以让位图有自我描述能力。 2.关于原型 实际上,C语言除了寻常算数转换(即不同类型的操作数做类型提升),它的类型转换比一般人想象的要广泛的多,在设计小于int,double的表达式中,都可能发生类型转换。 在表达式中,小于int类型的数据类型,都会被提升为int,这个特性被称为类型提升。ANSIC对两个小于int的类型进行加法时,都会对两个类似进行类型提升,然后对两个int进行加法,再对结果进行裁剪,如果两个操作数相加不会发生溢出异常,那么实际执行时只需要产生小于int类型的运算结果,可以省略类型提升。类似的,float和double。 常见的类型提升有,char,位段,枚举,unsigned char,short,unsigned short,float,任何数组。前提是int能够容纳原先的数据,否则,提升为unsigned int。 注意:参数也会被提升。 因此,在隐式转化方面,要注意三点: 1.隐式转换是语言中的一种临机手段,方便编译器简化。把所有数据转换为同一的长度,极大的简化了代码的生成,这样,压栈的参数都是同一长度,运行时系统只需要知道参数的数目。 2.缺省的隐式转换,不影响正常编程。 3.隐式转换在设计原型的上下文中,非常重要。 K & R C的函数声明和定义: 声明: int fun(); 定义: int fun(a,b) int a; int b; { } ANSI C: 原型: int fun(int a,int b); 或 int fun(int,int); 定义 int fun(int a,int b) { } 由于有上亿行的C代码采用K&R C方式编程,ANSI C并没有明确规定在函数声明中使用空括号是被正式废弃的,也没有说明继续使用这种版本的形式会导致与未来版本不兼容。因此,这两种风格都会大量存在。 在K&R C风格的函数中传递一个短于int类型的整数,函数实际收到的是int类型,这叫整形提升,这样做的目的,早期是为了简化编译器的工作。同样,传递float类型的参数自动提升为double类型。但在被调用的函数体内,这些类型又被裁剪为相应的类型。这样所有的东西都是相同的长度,大大简化传参过程。注意:早起的编译器,只允许三种类型做参数,int,double,指针,因此,在传递参数时会发生类型提升,但在函数体内,根据函数定义时申明的形参类型,自动裁剪。 相反,如果使用ANSI C 的函数原型。则不进行这样的提升和裁剪,因为假定参数是准确声明的。那么,在K&C和ANSI C的函数使用中,如果使用混合方式,则可能会出现错误。 1.ANSI C的函数原型,K&R C的函数定义 2.K &R C的函数原型,ANSI C的函数定义 这两种情况,在使用较窄的类型时,都会失败。 因为实际传递的参数类型(函数调用时)和期望接收(函数体内)的类型不一致,出现传参失败。 3.在实际编程中,我们把函数原型放置在头文件中,把函数定义放置在包含该头文件的文件中,编译器能同时发现他们。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |