所有的C程序都做同一件事,即观察一个字符,然后啥也不干。 ---Peter Weinberger
Good books:
C Traps and Pitfalls
The C Puzzle Book
Obfuscated C and Other Mysteries
C语言编程是一项技艺,需要多年历练才能达到完善的境界。想要品味出C语言的细微之处,并通过大量编写各种不同的程序成为C语言专家,则耗时甚巨。
编程专家在多年的实践中建立了自己的技术工具箱,里面是形形色色的习惯用法、代码片段和灵活掌握的技巧。他们汲取其他成功者的经验教训,或者直接领悟他们的代码,或者在维护他人的代码时聆听他们的教诲,随着时间的推移,逐步形成了这些东西。成为C编程高手的另一种途径是自省,即在认识错误的过程中进步。
//错误地使用了赋值运算符和等于运算符
#include
int main() {
//1.1
if (i = 3) ; //wrong
//1.2
if (i == 3) ; //right
//1.3
if (3 == i) ; //be supposed to suggest
//attempted assighment to literal
}
C语言的表达能力也实在是强,编译器对于“求一个表达式的值,但不使用该值”这样的语句也能接受,并且不发出任何警告,只是简单地把返回结果丢弃。
有些lint程序已经能够检测到这类问题,但人们很容易忽视这些有用的工具。
//只适用于小型程序片段,现实中的程序不可如此:
char pear[40];
double peach;
int mango = 13;
long melon = 2001;
关键字:char、double、int、long
变量名:pear、peach、mango、melon
幽默对于学习新东西是相当重要的。
读者可以把本书当做C语言编程的思路集锦,或是C语言提示和习惯用法的集合,也可以从经验丰富的编译器作者那里汲取营养,更轻松地学习ANSI C。
Enforce In_Order Execution of I/O (在I/O中实行按顺序执行的方针)(IBM/Motorola/Apple PowerPC)tunefs(UNIX) 高级系统管理员用它修改文件系统的动态参数,并优化磁盘中文件块的布局。 在早期的tunefs在线手册上,也是以一个标题为“Bugs”的小节来结尾。内容如下:
Bugs:
这个程序本来应该在安转好的(mounted)和活动的文件系统上运行,但事实上并非如此。因为超级块(superblock)并不是保持在告诉缓冲缓冲区中,所以只有当该程序运行在未安装好的(dismounted)文件系统中时才有效。如果运行于根文件系统,系统必须重新启动。
你可以优化一个文件系统,但不能优化一条鱼。
如果忽略这段话,你就等着烦吧。一个UNIX里的怪物会不断地纠缠你,直到你受不了为止。
mounted 安装好的
superblock 超级快
dismounted 未安装好的
/*
**编程挑战
*/
1. 查看一下time_t的定义,它位于文件/user/include/time.h中。
解析:
#ifndef _TIME_T_DEFINED
#define _TIME_T_DEFINED
#ifdef _USE_32BIT_TIME_T
typedef __time32_t time_t;
#else
typedef __time64_t time_t;
#endif
#endif
#ifndef _TIME32_T_DEFINED
#define _TIME32_T_DEFINED
typedef long __time32_t;
#endif
#ifndef _TIME64_T_DEFINED
#define _TIME64_T_DEFINED
__MINGW_EXTENSION typedef __int64 __time64_t;
#endif
#define __int64 long long
2.编写代码,在一个类型为time_t的变量中存放time_t的最大值,然后把它传递给ctime()函数,转换为ASCII字符串中并打印出来。注意ctime()函数同C语言并没有任何关系,它只表示“转换时间” 。
/*ctime(time_t *t)函数,转换成ASCII字符串并打印出来。注意ctime()函数同C语言没有任何关系, *它只表示“转换时间”。
*/
/*time_t的最大值
*/
/*time()获得当前的时间
*difftime()获得当前时间和time_t所能表示的最大时间值之间的差值(以秒计算)
*/
#include
#include
int main() {
printf("%u %u\n", sizeof(long), sizeof(time_t));
time_t biggest = 0x7FFFFFFF;
//time_t biggest = 0x7FFFFFFFFFFFFFFF;
printf("biggest = %s\n", ctime(&biggest));
return 0;
}
/*ctime()函数把参数转换为当地时间,跟世界统一时间UTC(格林尼治时间)并不一致,取决于你所在 *的时区,而且现在的年份跟最大时间值的年份相差甚远
*/
/* 输出:
*/
#include
#include
int main() {
time_t biggest = 0x7FFFFFFF;
printf( "sizeof(time_t) = %zd\n", sizeof(time_t) );
printf("biggest = %s\n", asctime(gmtime(&biggest)));
return 0;
}
/*gmtime()函数来取得最大的UTC时间值。这个函数并不返回一个可打印的字符串
*asctime()函数来获取一个这样的字符串
*/
/*但是,我们并未大功告成。如果你采用的是新西兰的时区,就会又多出13个小时,前提是新西兰在2038年仍然采用夏令时。新西兰在1月时采用的是夏令时(因为位于南半球)。但是,由于新西兰的最东端位于日界线的东面,在那里它应该比格林尼治时间晚10小时而不是早14小时。这样,新西兰由于其独特的地理位置,不幸成为该程序的第一个Bug的受害者。
*/
/* 输出:
*/
如果程序设计者去掉了程序的注释,那么多少年之后,他不得不担心该程序会在UNIX平台上溢出。请修改程序,找出答案。
1.调用time()获得当前的时间。
2.调用difftime()获得当前时间和time_t所能表示的最大时间值之间的差值(以秒计算)。
3.把这个值格式化为年、月、日、小时、分钟的形式,并打印出来。它是不是比一般人的寿命还要长?
#include
#include
#include
#include
int main( void ){
time_t t, t2;
long second;
t = time( &t );
t2 = LONG_MAX;
printf( "now date and time is: %s", ctime( &t ) );
second = difftime( t2, t );
printf( "second = %ld\n", second );
struct tm* ptm;
ptm = localtime( &t2 );
printf( "year = %d\n", ptm->tm_year + 1900 );
printf( "month = %d\n", ptm->tm_mon + 1 );
printf( "week = %d\n", ptm->tm_mday / 7 );
printf( "day = %d\n", ptm->tm_wday );
printf( "hour = %d\n", ptm->tm_hour );
printf( "minute = %d\n", ptm->tm_min );
return EXIT_SUCCESS;
}
/* 输出:
*/