【C语言】整型提升和算术转换
慕雪年华

[toc]

整型提升

要想知道什么是整型提升,那就要从表达式求值说起

表达式求值

表 达 式 求 值 的 顺 序 一 部 分 是 由 操 作 符 的 优 先 级 和 结 合 性 决 定

同 样,有 些 表 达 式 的 操 作 数 在 求 值 的 过 程 中 可 能 需 要 转 换 为 其 他 类 型

什么是表达式? 举个最简单的例子

1
2
3
4
5
6
7
8
int main()
{
int a=3;
int b=5;
int c = a + b * 7;
//c的式子即为表达式
return 0;
}

而C的整个式子就是一个表达式求值

在这之中,参与计算的两个变量以及结果变量都是int类型,并不需要进行整型提升

在我们日常编写代码的时候,编译器经常会有隐式类型转换


隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转化为普通整型,这种转换称为整型提升

1
2
float f =3.14
int num =f;

在上面这个代码中就有隐式类型转换,由float型转换为int型

但是会有精度的丢失

此时num为3


我们知道,不同数据类型的数据大小如下

数据类型及大小

char字符数据类型4byte
short短整型2byte
int整型4byte
long长整型4(32), 8(64)
long long长长整型8byte
float单精度浮点型(实型)4byte
double双精度浮点型(实型)8byte

可以看到,short类型和char类型的字节数都是小于int类型的

当我们将一个int类型的数据存放到char中时,会发生截断

截断&提升

把四个字节放在1个字节的内容中,截断,只保留一个字节

把数字5放入char类型中,5的4个字节的内容会被截断

示例

1
2
3
char a = 3;
//00000000000000000000000000000011 为3的二进制
//00000011 -a

在char类型a中,只存放了3的后8位(1个字节)的内容

这就是截断的表现形式


在char类型数据的表达式求值中,就会发生整型提升

规则如下:

把最高位视为符号位进行提升,在a和b的8位码前加24个0或1

代码示例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
int main()
{
char a = 3;
//00000000000000000000000000000011 为3的二进制
//00000011 -a
char b = 127;
//00000000000000000000000001111111 为127的二进制
//01111111 -b
char c = a + b;
//把最高位视为符号位进行提升
//在a和b的8位码前加24个0
//00000000000000000000000000000011
//00000000000000000000000001111111
//00000000000000000000000010000010

//10000010 为char c
//11111111111111111111111110000010 -补码
//11111111111111111111111110000001 -反码
//10000000000000000000000001111110 -原码
// -126
//发现a和b都是char类型的,都没有达到一个int的大小
//这里就会发生整型提升
printf("%d\n", c);//%d是有符号数,打印原码
return 0;
}

编译器中,负数是以补码的形式存放的

但在使用的时候,要先转换成原码再计算其数值

代码示例2

再来看一个比较大小的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;

if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");

return 0;
}

猜猜打印结果是什么?

是这个吗?

1
2
3
a
b
c

错!

image

运行后,我们会发现编译器只打印了c这个字符

因为if只会比较整型

而char和short类型都不足4个字节,在比较的时候需要进行整型提升

提升之后的结果与原数据不同

而int c本身就是整型,无须进行整型提升

1
int c = 0xb6000000;

所以代码只打印了字符c


代码示例3

再来看下面的这个代码,打印的结果是几呢?

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
short s = 5;
printf("%u\n", sizeof(s = a + 3));

return 0;
}

结果为2

因为最后的s是短整型,推断出来的长度为2


代码示例4 -sizeof

1
2
3
4
5
6
7
8
9
10
int main()
{
char c=1;
printf("%u\n",sizeof(c));//1
printf("%u\n",sizeof(+c));//4
printf("%u\n",sizeof(-c));//4
printf("%u\n",sizeof(!c));//4

return 0;
}

当+c和-c参与计算的时候,就会进行整型提升

这里涉及到了另外一个重要的知识点,sizeof括号中表达式的问题

下篇博客会详细介绍!


算术转换

说完整型提升,接下来就是和隐式类型转换很像的算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另外一个操作数的类型,否则操作就无法进行。

下面的层次体系称为寻常算术转换

long double
double
float
unsigned long int
long int
unsigned int
int

具体是怎么转换的呢?

在进行运算的时候,如果某个操作数的类型在上表中排名较低,那么首先要转换为另外一个操作数的类型后,再执行运算。

简单地说,就是从下往上转换

注意:算术转换要合理,不然会有潜在的问题


代码示例1

下面的是一个简单算术转换的示例

在int型和float类型一起计算的时候

int类型会转换为float类型进行计算

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h> 

int main()
{
int a=3;
float f =5.5;
float ra =a+f;
//算术转换,int-->float

return 0;
}

表达式属性

这里可以引出另外一个知识点,表达式的属性

表达式的两个属性:

  • 值属性
  • 类型属性

如以下代码中

  • a+b的结果30就是这个表达式的指属性

  • 类型属性是int

1
2
3
4
5
6
7
8
9
int main()
{
int a =10;
int b=20;
a+b;//表达式2个属性:值属性,类型属性
//30 值属性
//int 类型属性
return 0;
}

结语

本篇博客到这里就结束了

如果对你有帮助的话,还请点个赞再走吧!

这对我非常重要!