鹏哥C语言72---操作符与表达式求值

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>

//---------------------------------------------------------------------------------------------------------------操作符-12. 表达式求值
//表达式求值的顺序一部分是由  操作符  的优先级和结合性  决定。
//同样, 有些表达式的操作数在求值的过程中可能需要转换为其他类型。

//-------------------------------------------------------------------------------------------------------12.1隐式类型转换
//C的整型算术运算总是至少以缺省(默认)整型类型的精度来进行的。
//为了获得这个精度, 表达式中的字符和短整型操作数在使用之前被转换为普通整型, 这种转换称为整型提升。

int main()
{
    char a = 5;
    char b = 126;
    char c = a + b; //运算前需要先把 a,b整型提升为 int 类型
    printf("%d\n", c);
    return 0;
}

整型提升的意义 :
表达式的整型运算要在CPU的相应运算器件内执行, CPU内整型运算器(ALU)的操作数的字节长度,
一般就是int的字节长度, 同时也是CPU的通用寄存器的长度。

因此, 即使两个char类型的相加, 在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以, 表达式中各种长度可能小于int长度的整型值, 都必须先转
换为int或unsigned int, 然后才能送入CPU去执行运算。
 

如何进行整体提升呢?
整形提升是按照变量的数据类型的符号位来提升的

//-------------------------------------------------负数的整形提升
char c1 = -1
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111

//-------------------------------------------------正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//------------------------------------------------无符号数整型提升,高位补0

 //-----------------------------------------------------------------------整型提升举例1

int main()
{
    char a = 5;
    //5的2进制序列,4个字节,32bit
    //00000000000000000000000000000101  5的补码
    //char a---------------00000101
    char b = 126;
    //126的2进制序列,4个字节,32bit
    //00000000000000000000000001111110  126的补码
    //char b--------------01111110
    char c = a + b; 
    //char a---------------00000101
    //char b---------------01111110
    //表达式中的字符和短整型操作数在使用之前被转换为普通整型
    //00000000000000000000000000000101---a
    //00000000000000000000000001111110---b
    //00000000000000000000000010000011---c
    //char c---------------10000011
    //负数整型提升
    //11111111111111111111111110000011---c的补码
    //转为原码
    //10000000000000000000000001111101----   -125
    
    printf("%d\n", c); // -125
    return 0;
}

//-----------------------------------------------------------------------整型提升举例2

int main()
{
    char a = 0xb6;
    short b = 0xb600;
    int c = 0xb6000000;
    if (a == 0xb6) // a整型提升了
        printf("a"); //不打印
    if (b == 0xb600) // b整型提升了
        printf("b"); //不打印
    if (c == 0xb6000000) //c 不需要整型提升
        printf("c"); //打印
    return 0;
}

//-----------------------------------------------------------------------整型提升举例3

int main()
{
    char c = 1;
    printf("%u\n", sizeof(c));//1
    printf("%u\n", sizeof(+c));//4
    printf("%u\n", sizeof(-c)); //4
    return 0;

}

//-------------------------------------------------------------------------------------------------------12.2 算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
long double
double
float
unsigned long int
long int
unsigned int
int

//如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
//但是算术转换要合理,要不然会有一些潜在的问题。


//-------------------------------------------------------------------------------------------------------12.3 操作符的属性
复杂表达式的求值有三个影响的因素。
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

//操作符优先级
//表格
//-------------------------------------------------------------------问题表达式/代码

int main()
{
    3 + 2 * 4 + 5;
    //优先级只在相邻操作符中考虑
    3 * 4 + 5 * 2 + 8 * 5; //有多种求值路径----------是问题表达式 1
    int c = 2;
    c+--c; //------------------------------问题表达式 2

    int i = 10;
    i = i-- - --i * (i = -3) * i++ + ++i; //---------- 问题表达式 3 
    printf("i =%d\n", i);

    return 0;
}

//----------------------------------------问题代码 4

int fun()
{
    static int count = 1;
    return ++count; //由于 static,每次进入函数,count都不会销毁,每次调用函数,都会返回不同的count值
}
int main()
{
    int answer;
    answer = fun() - fun() * fun();
    printf("%d\n", answer);//输出多少?
    return 0;
}

// ----------------------------------------问题代码 5

int main()
{
    int i = 1;
    int ret = (++i) + (++i) + (++i); //求解路径不唯一
    printf("%d\n", ret);  // b是多少?
    printf("%d\n", i);  // i是多少?
    //不同编译器/服务器下,答案不同
    //因为求值路径不唯一,不同不同编译器/服务器选择的计算路径不同
    return 0;
}

//总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值