下面是一些通常的检查要点:
² 未初始化的局部变量
² 整数上溢, 特别是在一些16 比特的机器上, 一些中间计算结果可能上溢, 象a * b / c
² 未定义的求值顺序
² 忽略了外部函数的说明, 特别是返回值不是int 的函数, 或是参数“缩小” 或可变的函数
² 复引用空指针
² malloc/free 的不适当使用: 假设malloc 的内存都被清零、已释放的内存还可用、再次释放已释放内存、malloc 的内部被破坏
² 指针类常规问题
² printf() 格式与参数不符, 特别是用%d 输出long int
² 试图分配的内存大小超出一个unsigned int 类型的范围, 特别是在内存有限的机器上
² 数组边界问题, 特别是暂时的小缓冲, 也许用于sprinf() 来构造一个字符串
² 错误的假设了typedef 的映射类型, 特别是size t
² 浮点问题
² 任何你自己认为聪明的在特定机器上的机器代码生成小技巧
“Segmentation violation”, “Bus error” 和“General protectionfault” 意味着什么?
通常, 这意味着你的程序试图访问不该访问的内存地址, 一般是由于堆栈出错或是不正确的使用指针。可能的原因有: 局部数组溢出(用堆栈分配的自动变量);不小心, 用了空指针、未初始化指针、地址未对齐的指针或其它没有适当分配的指针; malloc 内部被破坏; 函数调用参数不匹配, 特别是如果用了指针, 两个可能出错的函数是scanf()和fprintf() (确定他的第一个参数是FILE *)。
“印第安山风格指南” (Indian Hill Style Guide)
用gcc -Wall -pedantic替代lint
怎样显示一个百分比或“转动的短棒” 的进展表示器?
这个简单的事情, 你可以做到相当的可移植。输出字符’\r’ 通常可以得到一个回车而没有换行, 这样你就可以复写当前行。字符’\b’ 代表退格, 通常会使光标左移一格。记住要调用fflush()。
使用数据库来取代平坦文件
怎样抓获或忽略像control-C 这样的键盘中断?
基本步骤是调用signal():
#include <signal.h>
singal(SIGINT, SIG_IGN);
就可以忽略中断信号, 或者:
extern void func(int);
signal(SIGINT, func);
使程序在收到中断信号时, 调用函数func()。
怎样判断机器的字节顺序是高字节在前还是低字节在前?
有个使用指针的方法:
int x = 1;
if(*(char *)&x == 1)
printf("little-endian\n");
else
printf("big-endian\n");
另外一个可能是用联合。
从其他语言转换到C的工具:p2c, ptoc, f2c
由一个日期, 怎样知道是星期几?
这个由Tomohiko Sakamoto 提供的优雅的代码:
int dayofweek(int y, int m, int d) /* 0 = Sunday */
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
自打印程序:
char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}
还有一个有James Hu 发布的改进版:
#define q(k)main(){return!puts(#k"\nq("#k")");}
q(#define q(k)main(){return!puts(#k"\nq("#k")");})
什么是“达夫设备” (Duff’s Device)?
这是个很棒的迂回循环展开法, 由Tom Duff 在Lucasfilm 时所设计。它的“传统” 形态, 是用来复制多个字节:
register n = (count + 7) / 8; /* count > 0 assumed */
switch (count % 8)
{
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
这里count 个字节从from 指向的数组复制到to 指向的内存地址(这是个内存映射的输出寄存器, 这也是为什么它没有被增加)。它把swtich 语句和复制8 个字节的循环交织在一起, 从而解决了剩余字节的处理问题(当count 不是8 的倍数时)。相信不相信, 象这样的把case 标志放在嵌套在swtich 语句内的模块中是合法的。当他公布这个技巧给C 的开发者和世界时, Duff 注意到C 的swtich 语法, 特别是“跌落” 行为, 一直是被争议的, 而“这段代码在争论中形成了某种论据, 但我不清楚是赞成还是反对”。