依赖编程内部知识的C语言习惯用法

1.关于位图的自描述能力

图标或者图形是一种小型的位模式映射于屏幕产生的图像,

实际上,其实就是用原本十六进制表示的位图数组,表示为二进制方式分解方式。例如:

0x07c6,二进制就是0000011111000110,即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
#define _ )*2
#define s ((((((((((((((((0

则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.在实际编程中,我们把函数原型放置在头文件中,把函数定义放置在包含该头文件的文件中,编译器能同时发现他们。

 

 

你可能感兴趣的:(依赖编程内部知识的C语言习惯用法)