C Primer Plus笔记(2)

第五、六、七章 类型转换特点与逻辑表达式断路短路(序列点与副作用)

C的数据类型会在一些语句中自动转换,从高到低为long double>double>float>unsignedlong long>long long>unsigned long>long>unsigned int>int(在long和int长度一致时,unsigned int>long),有几种不同情况:

1、将int类型的数据计算结果赋值给long或者double等等,会提升成相应的数据类型再赋值。反过来赋值就会导致降级,降级根据具体实现方式不同也有不同情况,不建议使用,很容易出错。

2、将int和float的混合计算,这俩都会先升级再计算,以保证计算不会超出数据范围导致出错。

3、当类型转换出现在表达式时,所有char和short型都会转换成int或unsigned int,float会转换成double,这种就是升级转换。如同C Primer Plus在P84中提到的float型参数转换,在printf打印时,会自动将其提升为double型,在P89提到的参数传递中,也可以看见,float在数据栈中的保存占了8字节,和double一样大。

4、数据作为函数参数传递时,char、short转为int,float转为double,同上。

逻辑表达式的短路断路属于逻辑运算的特色。
A||(或)B,若A为真,则结果必真,无须看B的真假
A&&(且)B,若A为假,则结果必假,无须看B真假。

现在有这样一个表达式:4>3 || i++ ,如果这个表达式单独存在在某一行,那么它的值是1,并且不会使得 i 自加。我一直认为逻辑表达式的断路短路只存在于判断语句的条件中,现在才知道,原来这是逻辑表达式自己的特性,或者说是&& || 所带来的特性。
程序如下:

#include<stdio.h>
int main()
{
    int i=0;
    4>3 || i++;
    printf("now i equals %d \n",i);
    4<3 && i--;
    printf("now i equals %d \n",i);
    return 0;
}

输出结果:在这里插入图片描述

可以看到,i 两次变化的运算都被跳过了,第一次被短路,走真路线;第二次被断路,断在假路线。

我们改变逻辑运算式的顺序,观察一下有何改变:

#include<stdio.h>
int main()
{
    int i=0;
    i++ || 4>3;
    printf("now i equals %d \n",i);
    i-- && 4<3 ;
    printf("now i equals %d \n",i);
    return 0;
}

结果:在这里插入图片描述
改变顺序之后,i 终于按照规定路线变化了。

顺便在这个程序上测试++i 和 i++的不同:

//try1.c
#include<stdio.h>
int main()
{
    int i=0,j=0;

    printf("i = %d \n",i++);

    printf("j = %d \n",++j);
    return 0;
}

结果是:
i = 0
j = 1

//try2.c
#include<stdio.h>
int main()
{
    int i=0,j=0;
    i++ && printf("i = %d\n",i);
    printf("i = %d\n",i);
    ++j && printf("j = %d\n",j);
    printf("j = %d\n",j);
    return 0;
}

结果是:
i = 1
j = 1
j = 1

我们改进一下程序:

//try3.c
#include<stdio.h>
int main()
{
    int i=1,j=1;
    i++ && printf("i = %d\n",i);
    printf("i = %d\n",i);
    ++j && printf("j = %d\n",j);
    printf("j = %d\n",j);
    return 0;
}

结果:
i = 2
i = 2
j = 2
j = 2

在这里,先把序列点和副作用说完再解释上述现象的原因。
副作用就是对数据对象或文件的修改,比如a=10;C语言会对这个表达式求值:10,然后带来的副作用才是将10赋给a。printf打印也是求值,printf()会返回打印的字数,而显示出来是它的副作用。
序列点标志着前面表达式的结束,在该序列点上,所有的副作用都在进入下一步之前发生。也就是之前的表达式该求值的求值,该自加的自加,搞定之后再去做后面的事。一个完整的表达式(完整表达式(full expression),就是指这个表达式不是另一个更大表达式的子表达式)的结束就是一个序列点,且&&、|| 、,(逗号)也都是序列点。

在try1.c中,i j 的不同是由于++i 的值可在打印语句执行,i++ 的值要到打印结束后可用。不推荐这样写代码,没有意义还容易弄错。

在try2.c中,应该打印两次 i 的值和两次 j 的值,但是这里少了 i 的第一次,因为断路了,i ++所得到的1要到副作用生效后才赋给 i ,副作用就在 && 运算符上生成。但 j 不同,++j 使得 j = 1,所以逻辑运算式没有断路,打印了两个结果。

在try3.c中,我们梳理一下程序流程,首先 i++,此时逻辑判断使用的 i 值为定义时赋的1。接着到了 && 序列点,i++副作用使得 i = 2,之后打印 i 结果为2。j 的流程和try2.c的类似。

所以, i++ && printf(“i = %d\n”,i);这个表达式相当于 i++; printf(“i = %d\n”,i);

++i和i++的区别可以认为是在序列点结算的时候和print的优先度不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值