C专家编程 第1章 C:穿越时空的迷雾 1.10 “安静的改变”究竟有多少安静

本文探讨了C语言中的算术转换规则,包括K&R和ANSI C的标准。在不同类型的算术操作中,数据类型会根据规则进行提升或转换,可能导致不同的结果。例如,无符号整数与有符号整数相减可能会产生非预期的正数。建议尽量避免在代码中滥用无符号类型,以减少潜在的复杂性和边界问题。同时,理解这些转换对于编写健壮的C程序至关重要。
摘要由CSDN通过智能技术生成

    1.10 "安静的改变"究竟有多少安静
    目的是使C语言更加可靠。

    算术转换(K&R C)
    操作数              转换类型 
    寻常算术转换(usual arithmetic conversion)
    操作数为char或short会转变成int
    操作数为float会转变成double
    首先,其中一个操作数为double,其他类型会转换成double,结果类型也为double(优先级较高) 
    其次,其中一个操作数为long,其他类型会转换成long,结果类型也为long类型 
    最后,其中一个操作数为unsigned,其他类型会转换成unsigned, 结果类型为unsigned类型
    其他情况,如果两个操作数的类型都为int,计算结果的类型也是int
    算术转换(ANSI C)
    字符和整型(整型升级) 
    char、short int或者int型位段(bit-field),包括它们的有符号或无符号变体,以及枚举类型,可以使用在需要int或unsigned int的表达式中。如果int可以完整表示源类型的所有值,那么该源类型的值就被转换为int,否则转换为unsigned int。这称为整型升级。
    寻常算术转换
    许多操作数类型为算术类型的双目会引发转换,并以类似的方式产生结果类型。
    它的目的是产生一个普通类型,同时也是结果的类型。这个模式称为“寻常算术转换”。
    首先,一个操作数类型为long double,另一个操作数类型也被转换成long double
    其次,一个操作数类型为double, 另一个操作数类型也被转换成double
    最后,一个操作数类型为float, 另一个操作数类型也被转换成float
    否则,两个操作数进行整型升级,并执行下面的规则
    如果其中一个操作数的类型为unsigned long int,那么另一个操作数也被转换成unsigned long int。其次,如果其中一个操作数的类型为long int,而另一个操作数类型是unsigned int,如果long int能够完整表示unsigned int的所有值,那么unsigned int类型操作数被转换成long int;
    如果long int不能完整表示unsigned int的所有值,那么两个操作数都被转换成unsigned long int。
    再次,如果其中一个操作数的类型为long int, 那么另一个操作数被转换为long int。
    最后,如果其中一个操作数的类型是unsigned int, 那么另一个操作数也被转换成unsigned int。
    如果所有以上情况都不属于,那么两个操作数都为int。
    浮点操作数和浮点表达式的值可以用比类型本身所要求的更大的精度和更广的范围来表示,而它
的类型并不因此改变。
    ANSI C标准所表示的意思大致如下:
    当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,长度更长的方向转换。整型数如果转换为signed不会丢失信息,就转换为signed,否则转换为unsigned。
    K&R C采用无符号保留(unsigned preserving)原则,就是当一个无符号类型与int或者更小的整型混合使用时,结果类型为无符号类型。
    ANSI C标准采用值保留(value preserving)原则,就是当把几个整型操作数混合使用时(如下面的程序所示),结果类型既有可能是有符号数,也可能是无符号数,具体取决于操作数的类型的
相对大小。 

    #include <stdio.h>

    int main( void ){
        if( 1u - 2 >= 0 ){
            printf( "the result of unsigned int number substract signed int number is larger than or equal to zero" );
        } else{
            printf( "the result of unsigned int number substract signed int number is smaller than zero");
        }
    
        return 0;
    }

输出:

你可以尝试把2改变为2l或者2ll,看看有啥变化?或许你会大吃一惊!!!

    #include<stdio.h>

    int main() {
        if (-1 < (unsigned char) 1) { //equivalent to (int)-1 < (int)1 
            printf("-1 is less than (unsigned char)1: ANSI semantics");
        } else {                      //equivalent to (unsigned int)(-1) < (unsigned int)1
            printf("-1 NOT less than (unsigned char)1: K&R semantics");
        }
        return 0;
    }

输出:

    程序中的表达式在两种编译器下的编译器结果不同。-1的位模式是一样的,但一个编译器(ANSI C)将它解释为负数,另一个编译器(K&R C)却将它解释为无符号数,也就是变成了正数。 

    软件信条

    #include <stdio.h>
    int array[] = {23, 34, 12, 17, 204, 99, 16};
    #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) //无符号整数(unsigned int) 
    int main() {
        int d = -1, x;
        // /*...*/
        //error equivalent to (unsigned int)d <= (unsigned int)TOTAL_ELEMENTS - 2
        if (d <= TOTAL_ELEMENTS - 2) {
            x = array[d + 1];
        }
        // /*...*/
        //correct //equivalent to (int)d <= (int)TOTAL_ELEMENTS - 2
        if (d <= (int)TOTAL_ELEMENTS - 2) {
            x = array[d + 1];
        }
    } 
    #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
    #define TOTAL_ELEMENTS (sizeof(array) / sizeof(int))
    因为前者可以在不修改#define语句的情况下改变数组的基本类型。 

    无符号类型的建议
    尽量不要在代码中使用无符号类型,以免增加不必要的复杂性。尤其是不要仅仅因为无符号不存在负值(如年龄、国债)就用它来表示数量。
    尽管使用像int那样的有符号类型,这样在涉及升级混合类型的复杂细节时,不必担心边界情况(如-1被翻译为非常大的正数)。 
    只有在使用位段和二进制掩码时,才可以使用无符号数。
    应该在表达式中使用强制类型转换,使操作数均为有符号数或者无符号数,这样不必由编译器来选择结果的类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weixin_40186813

你的能量无可限量。

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

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

打赏作者

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

抵扣说明:

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

余额充值