printf(" %d",sizeof'A');输出的结果是4,而不是字符的长度1,因为它根据类型提升规则把char->int,因此结果自然为4了。
在K&R中,在表达式里,每个char都被转换为int,float被转换为double,由于函数参数也是一个表达式,所以当参数传递给函数时也会发生类型转换。但在ANSI C中,有个例子:
float f1, f2;
double d;
f1 = f2*d;
如果编译器可以确定用float进行运算的结果跟转换为double后进行运算的结果一样,那么也可以使用float来进行乘法运算。如果编译器能够保证运算结果一致,也可以省略类型提升--这通常出现在表达式中存在常量操作数的时候。
char, bit-field, enum, unsigned char, short, unsigned short, 会被提升为int ,而float被提升为double,任何数组则被提升为相应类型的指针。
在ANSI C中,如果使用了适当函数原型,类型提升便不会发生,否则也会发生。在被调用函数的内部,被提升后的参数被裁减为原先声明的大小。int printf(const char *format, ....);表示它是一个接受可变参数个数的函数,参数的信息(除了第一个以外)均未给出,此时一般的参数提升始终会发生。
K&R C: 声明:int foo();
定义:
int foo(a, b)
int a;
int b;
{
}
ANSI C 原型: int foo(int a, int b); or int foo(int, int );
定义:int foo(int a, int b){ ….}
在K&R C中,如果向函数传递一个短于int的整数,函数实际接收到得是int,如果传递的是一个float,则实际接收到的是double。在被调用的函数体内,这些值会根据函数定义时的参数声明类型自动裁剪为该类型。
1. K&R C函数声明和K&R C函数定义:顺利调用,参数进行类型提升
2. ANSI C函数声明(原型)和ANSI C函数定义:顺利调用,所传递的参数为实际的参数
3. ANSI C函数声明(原型)和K&R C函数定义:如果使用一个较短的类型就会失败!函数调用时所传递的是实际类型,而函数期望接受的是提升后的类型。
4. K&R C函数声明和ANSI C函数定义:如果使用一个较短的类型就会失败!函数调用时所传递的是提升的类型,而函数期望接受的是实际的类型。
所以不要用两种风格的混搭,最好是将函数的原型放在头文件中,函数的定义放在另一个包含头文件的源文件中。
调用函数库之后检查errno变量,它是一个全局变量,属于ANSI C标准,如果一个库函数调用活系统调用出现了问题,他将会设置errno的值以提示问题的原因。
FSM(finite state machine)是一个数学概念,它是一种协议,用于有限数量的子程序(状态)的发展变化,每个子程序进行一些处理并选择进入下一种状态。他特别适用于基于输入的在几个不同的可选动作中进行循环的程序尤其合适。如:投币售货机就具有“接收硬币”,“选择商品”,“发送商品”,“找零钱”几种状态。它的输入时硬币,输出是商品。
基本思路:用一张表保存所有可能的状态,并列出进入每个状态时可能执行的所有动作,其中最后一个动作就是计算下一个应该进入的状态,不停的在各种状态间转换,知道达到结束状态。
C中可以使用基于函数指针的数组来实现,如:声明:
void (*state[MAX_STATES])();
初始化: extern int a(), b(), c(), d();
int (*state[])() = {a,b,c,d};
调用: (*state[i])() 所有的函数必须接收同样的参数,并返回同种类型的返回值(除非你把数组元素做成一个联合)
其他实现方法:1. 让状态函数返回一个指向通用后续函数的指针,并把它转换为适当的类型。
2. 使用switch语句,赋值给控制变量并把switch语句放在循环的内部
3. 如果状态函数需要多个不同的参数,可以使用一个参数计数器和一个字符串指针数组,类似main中的int argc, char *argv[]
散列表:散列函数产生一个0-表长度减1的值,作为数据的位置,这样把数据和存储他的位置联系起来。在每个位置的后面挂一个链表,所有散列函数值为这个位置的元素都添加到这个链表中。甚至可以为这个位置后面再挂一个散列表。当查找一个数据项时,先产生该数据项的散列函数值,并根据这个值,找到表中相应的位置,并从该位置开始查找数据,从而不用从表的第一个元素开始查找。
可调式性编码:把系统分成几个部分,先让程序总体结构运行,只有基本的程序能够运行后,才为那些复杂的细节完善、性能调整、和算法优化。
复杂的类型转化步骤:
1. 一个对象的声明,它的类型就是想要转的结果类型
2. 删去标示符(以及任何如extern之类的存储限定符),并把剩余的内容放在一对括号里。
3. 把第2步产生的内容放在需要进行类型转换的对象的左边。
例如用于qsort()的比较函数声明为:int intcompare(const int *i, const int *j) 调用qsort()时为:qsort(a,10,sizeof(int),(int(*)(const int *, const int *))intcompare);