C专家编程 前言

本文摘自《C专家编程》,探讨了C语言中的一些常见陷阱,如误用赋值运算符和等于运算符。文章提醒程序员注意编译器可能忽视的潜在问题,并提供了编程挑战,例如检查time_t的最大值并理解其含义。通过幽默和实例,帮助读者深化对C语言的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    所有的C程序都做同一件事,即观察一个字符,然后啥也不干。     ---Peter Weinberger 

    Good books: 
    C Traps and Pitfalls
    The C Puzzle Book
    Obfuscated C and Other Mysteries

    C语言编程是一项技艺,需要多年历练才能达到完善的境界。想要品味出C语言的细微之处,并通过大量编写各种不同的程序成为C语言专家,则耗时甚巨。

    编程专家在多年的实践中建立了自己的技术工具箱,里面是形形色色的习惯用法、代码片段和灵活掌握的技巧。他们汲取其他成功者的经验教训,或者直接领悟他们的代码,或者在维护他人的代码时聆听他们的教诲,随着时间的推移,逐步形成了这些东西。成为C编程高手的另一种途径是自省,即在认识错误的过程中进步。 

    //错误地使用了赋值运算符和等于运算符

    #include <stdio.h>
    int main() {
        //1.1
        if (i = 3) ; //wrong 
        //1.2
        if (i == 3) ; //right
        //1.3
        if (3 == i) ; //be supposed to suggest 
        //attempted assignment 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 <stdio.h>
    #include <time.h>

    int main() {
        printf("%zd %zd\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 <stdio.h>
    #include <time.h>

    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 <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <limits.h> 

    int main( void ){
        time_t t, t2;
        int second;
    
        t = time( &t );
        t2 = LONG_MAX;
        printf( "INT_MAX = %d\n", INT_MAX );
        printf( "now date and time is: %s", ctime( &t ) );
        second = difftime( t2, t );
        printf( "second = %d\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;
    } 

输出:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值