表达式求值 - 整形提升和截断

一、整形提升

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

所以,整形提升的对象是:字符类型(char),短整形(short)。

示例如下:
在这里插入图片描述
注意: 整形提升是对补码进行的操作。

二、为什么要整形提升?

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的变量相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

三、截断

截断指的是长字节类型在转换成长字节类型时,进行的取部分比特位的现象。

示例如下:
在这里插入图片描述
注意: 截断是对补码进行的操作。

四、示例

截断和整形提升一般会同时出现,而且很容易被忽略,下面通过一个示例来具体了解一下截断和整型提升。

int main()
{
	char c1 = 5;		// 1
	char c2 = 127;		// 2
	char c3 = c1 + c2;  // 3
	printf("%d\n",c3);  // 4
}

为了方便描述,将上面的几行代码进行了标号,下面我们一部分一部分的看。

1,2

char c1 = 5;		// 1
char c2 = 127;		// 2

12 是初始化操作,分别将 5127 赋值给 c1c2,但是 5127 是整形,属于 int 类型,而 c1c2char 类型的,所以赋值时由于类型转换会发生的截断。

注意: 截断是对补码进行的操作,而 5127 都是正数,原码 = 反码 = 补码。

在这里插入图片描述
所以 c1 的值就是 0000 0101(二进制),c2 的值是 0111 1111(二进制)。

3

char c3 = c1 + c2;  // 3

① c1 + c2

c1c2char 类型 ,两者要相加,需要进行整形提升,都成为 int 类型后,才能做加法。

  • 首先我们来看补位要补什么?
    ① 有符号的类型,高位是符号位,根据符号位补,符号位是几就补几。
    ② 无符号的类型,由小到大转化,缺位直接补0
    在这里插入图片描述
  • c1 和 c2 整形提升
    char 类型是有符号类型,两个的最高位都是 0,所以补位都补 0
    在这里插入图片描述
  • c1 和 c2 相加
    在这里插入图片描述
    两个 int 类型相加得到的结果也是 int 类型的。

② c3 = c1 + c2

  • 赋值时发生截断
    刚才我们得到了c1c2相加的结果,是 int 类型的,但该结果要赋值给 char c3(1 个字节),从 intchar 需会发生截断。
    在这里插入图片描述
    所以 c3 的值就是 1000 0100 了。

4

printf("%d\n",c3);  // 4

%d 打印的内容是 10 进制的有符号整形。

  • 所以首先就是将 char 类型的 c3 整形提升成int类型:
    在这里插入图片描述
    char 类型是有符号类型,符号位是 1,根据符号位进行补位都补 1

  • 然后就是打印 10 进制数字,但此时我们得到的值的补码,要想得到 10 进制数字,需要转成原码,转换规则如下:
    在这里插入图片描述
    转换结果:
    在这里插入图片描述
    所以最终打印出来的结果是 -124


本文到这里就结束了,如果对您有帮助,希望得到一个赞!🌷
如有错漏,欢迎指正!😄

<think> 我们之前讨论的代码中,整数提升(integer promotion)确实发生了,但它并没有改变最终结果。让我详细解释一下。 ### 整数提升(Integer Promotion)的概念 在C语言中,当表达式中使用小于`int`的类型(如`char`、`short`)时,它们会被自动提升为`int`(或`unsigned int`)类型,然后再进行运算。这个过程称为整数提升。 ### 代码分析(考虑整数提升) ```c #include <stdio.h> int main() { char a = 5; char b = 126; char c = a + b; // 这里发生整数提升,但最终结果被截断 printf("%d\n", c); return 0; } ``` #### 步骤分解: 1. **整数提升**: - 在计算`a + b`时,`a``b`都被提升为`int`类型(假设`int`为32位)。 - 提升后:`a`变成32位的5(二进制:`00000000 00000000 00000000 00000101`) - 提升后:`b`变成32位的126(二进制:`00000000 00000000 00000000 01111110`) - 相加:得到131(二进制:`00000000 00000000 00000000 10000011`) 2. **赋值回char**: - 将32位的131赋值给8位的`char c`时,发生截断(只保留低8位:`10000011`)。 - 由于`char`是有符号类型,`10000011`解释为有符号数,最高位是1,所以是负数。 - 负数在计算机中用补码表示,将`10000011`转换为十进制: - 补码:`10000011` → 取反:`01111100` → 加1:`01111101` → 125 → 所以原值是-125。 ### 为什么整数提升没有改变结果? 虽然计算时使用了更大的类型(32位),但最终结果被赋值给一个8位的`char`变量,因此发生了截断。所以最终结果还是-125。 ### 验证整数提升的存在 我们可以通过查看汇编代码或使用以下代码验证: ```c #include <stdio.h> int main() { char a = 5; char b = 126; // 查看a+b的类型 printf("Size of (a+b) is %zu\n", sizeof(a+b)); // 输出4(在32/64位系统中,int通常是4字节) return 0; } ``` 输出: ``` Size of (a+b) is 4 ``` 这证明`a+b`的结果是`int`类型。 ### 如果不想截断怎么办? 使用足够大的类型来存放结果: ```c #include <stdio.h> int main() { char a = 5; char b = 126; int c = a + b; // 不会截断,因为c是int类型 printf("%d\n", c); // 输出131 return 0; } ``` ### 总结 整数提升确实发生了,但赋值操作导致结果被截断回`char`,所以最终结果还是-125。 §§相关问题§§: 1. C语言中哪些情况下会发生整数提升? 2. 如何避免在整数运算中发生意外的截断? 3. 在C语言中,`char`类型到底是有符号还是无符号?标准是如何规定的? 4. 整数提升算术转换(arithmetic conversion)有什么区别? </think>您提出了一个非常关键的点!**整数提升(integer promotion)** 在这段代码中确实起着重要作用。让我详细解释整数提升如何影响计算结果: ### 整数提升的作用 在 C 语言中,当表达式中使用小于 `int` 的类型(如 `char`)时,编译器会自动将它们提升为 `int` 类型进行计算。这个过程称为整数提升。 #### 修改后的代码分析(考虑整数提升): ```c #include <stdio.h> int main() { char a = 5; // char 类型 char b = 126; // char 类型 // 整数提升发生在这里: // a b 被提升为 int 类型(通常是 32 位) int temp = a + b; // 实际计算使用 int 类型:5 + 126 = 131 // 然后将 int 结果赋值给 char 变量 char c = temp; // 131 被截断为 char 类型 printf("%d\n", c); // 输出截断后的值 return 0; } ``` ### 详细步骤解释 1. **整数提升阶段**: - `a` (char) 被提升为 int:值仍然是 5 - `b` (char) 被提升为 int:值仍然是 126 - 计算 `a + b` 使用 int 类型:5 + 126 = 131 2. **赋值阶段**: - 将 int 类型的 131 (二进制: `00000000 00000000 00000000 10000011`) - 赋值给 char 类型(8位),发生截断:只保留低 8 位 `10000011` - `10000011` 在有符号 char 中表示 -125(二进制补码) 3. **输出阶段**: - `printf("%d\n", c)` 将 c 提升回 int 类型输出 - 提升过程中符号位被保留,所以输出 -125 ### 整数提升的验证 我们可以通过以下代码验证整数提升: ```c #include <stdio.h> int main() { char a = 5; char b = 126; // 检查表达式 a + b 的类型 printf("Size of (a+b) is %zu bytes\n", sizeof(a + b)); // 输出 4(int 的大小) // 直接输出提升后的结果 printf("Promoted result: %d\n", a + b); // 输出 131 return 0; } ``` 输出: ``` Size of (a+b) is 4 bytes Promoted result: 131 ``` ### 关键结论 1. **整数提升确实发生了**:计算 `a + b` 是在 int 类型上进行的 2. **问题发生在赋值阶段**:当把 int 结果赋值给 char 变量时发生截断 3. **输出结果相同**:虽然计算时使用了更大的类型,但最终结果被截断后仍然是 -125 ### 如何避免截断问题 ```c #include <stdio.h> int main() { char a = 5; char b = 126; // 方法1:直接使用整型接收结果 int result1 = a + b; printf("Method 1: %d\n", result1); // 输出 131 // 方法2:显式类型转换 int result2 = (int)a + b; printf("Method 2: %d\n", result2); // 输出 131 return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值