【C】隐式类型转换

隐式类型转换是C语言在编译阶段自动进行的类型转换,无需程序员显式指定。它主要用于以下场景:

  • 表达式中操作数类型不同(如int + float)
  • 赋值时左右类型不匹配(如int = float)
  • 函数调用时参数类型不匹配(如传递char给int形参)

隐式转换的核心目标是保证运算的合理性和精度,但它可能带来意料之外的结果,需谨慎处理。

补充:浮点数和整型数之间无论是隐式转换还是强转,都是数值语义的转换,1.0转成int就是1,而不是内存值。只有用联合体或指针,才能取浮点数特殊的存储格式。

  • 整型提升时规则(低于int的,在计算时不管需不需要,都先统一到int,即使两边都是char):

有符号类型:高位填充符号位(负数补1,正数补0)(也适用于右移规则);

无符号类型:高位补0;

复制代码
unsigned char uc = 0xFF; //11111111
int i = uc;              //提升为int -> 00000000 00000000 00000000 11111111

***左移规则:低位补0;***单字节左移会触发整型提升,左移不大于24无需考虑强转uint64_t,大于24则一定要先强转再左移

右移规则:无符号数:高位补0;有符号数:高位补符号位;

  • 两个操作数类型不同时,按下方从低到高转换(低优先级直接变成高优先级):

char/short -> int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double

(unsigned int 比 int范围大,每个int包括负数都可以找到对应点,且计算逻辑没问题,信息不丢失。如果反过来,unsigned int的大值转成int变成了负数,虽然在int范围内合法,但是和原始数学意义完全割裂,导致信息丢失)

复制代码
char a = -1;
unsigned long aa = 1;
unsigned long long b = 1;
unsigned long long c = a * b;
unsigned long long d = a * aa * b;

printf("chenmin %lld %lld\n", c, d);
//结果是:chenmin -1 4294967295
//c是由a变int再变unsigned long long
//d是由a变int再变unsigned long再变unsigned long long,中间符号位丢失
  • 操作数精度相同,则计算结果类型不变,且中间过程无需转换。但是有需要的话我们可以借助整型提升时规则来理解过程和结果,比如INT32U的5-255实际计算过程都是INT32U(无需浪费资源),我们可以先假设提升了,得到-250,再转成一个很大的INT32U,之后再进行强转或者赋值操作。

INT64U = 0x1D000000 * 0x1D000000; //结果是0,两个32位的数先相乘溢出再赋值

INT64U = (INT64U)(0x1D000000 * 0x1D000000); //结果是0,两个32位的数先相乘溢出再赋值

常见陷阱:

1、符号位扩展混淆意图

复制代码
char c = -1;
unsigned int u = c; //c提升为int(0xFFFFFFFF) -> 转换为unsigned int为4294967295

unsigned int u = (unsigned char)c; //截断为0xFF

2、溢出截断,可借助0作为补码计算,比如-700赋值给char,-700+256+256+256 == 68

复制代码
int a = 50000;
short b = a; //若short为16位,b值为-15536(溢出)

3、类型提升导致正数小于负数

复制代码
unsigned int u = 10;
int s = -5;
if (u < s)
{
    //s被转换为unsigned int -> 4294967291
}

4、不同情况的整型提升

复制代码
unsigned int a1 = 9;
unsigned int b1 = 1000;

if (a1 - b1 > 1) //操作数精度相同,则计算结果类型不变,且中间过程无需转换
{
    printf("1 Hello world! %d\n", a1 - b1);
}

unsigned short a2 = 9;
unsigned short b2 = 1000;

if (a2 - b2 < 1) //低于int的,在计算时不管需不需要,都先统一到int
{
    printf("2 Hello world! %d\n", a2 - b2);
}

unsigned int a6 = 9;
unsigned int b6 = 1000;

if (a6 - b6 < -99) //常数的类型由变量类型决定
{
    printf("6 Hello world! %d\n", a6 - b6);
}

5、精度丢失

复制代码
float f = 0.1f;
double d = 0.1;
if (f != d)
{
    //因float精度不足,实际存储值与double不同
}

//建议:避免直接比较浮点数,使用误差范围
#define EPSILON 1e-6
if (fabs(f - d) < EPSILON)
{
    //近似相等
}
相关推荐
吃好睡好便好21 小时前
用while循环语句求和
开发语言·学习·算法·matlab·信息可视化
王璐WL1 天前
【C语言入门级教学】函数的概念2
c语言·数据结构·算法
不知名的忻1 天前
B 树与 B+ 树:面试完全指南
b树·算法·面试·b+树
运筹vivo@1 天前
2657. 找到两个数组的前缀公共数组 | 难度:中等
算法·leetcode·职场和发展·哈希表
索木木1 天前
NCCL SHARP 和 TREE算法
java·服务器·算法
古城小栈1 天前
Rust 调用 C 语言库 实战指南(企业级)
c语言·开发语言·rust
Lumbrologist1 天前
【C++】零基础入门 · 第 1 节:第一个程序 Hello World 与编译运行
开发语言·c++
枕星而眠1 天前
Linux 线程:原理、属性、实战与面试避坑
linux·运维·c语言·面试
_李小白1 天前
【C++学习笔记】新特性之inline变量
c++·笔记·学习
心中有国也有家1 天前
hccl 架构拆解:昇腾集合通信库到底在做什么?
人工智能·经验分享·笔记·分布式·算法·架构