【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)
{
    //近似相等
}
相关推荐
憨波个3 分钟前
【说话人日志】DOVER:diarization 输出融合算法
人工智能·算法·音频·语音识别·聚类
爱学习的张大5 分钟前
具身智能论文问答(四):pi0
人工智能·算法
楼田莉子7 分钟前
仿Muduo的高并发服务器:Channel模块与Poller模块
linux·服务器·c++·学习·设计模式
zhouwy1138 分钟前
Linux网络编程从入门到精通
linux·c++
迷途之人不知返8 分钟前
deque的简单认识
数据结构·c++
上弦月-编程10 分钟前
指针编程:高效内存管理核心
java·数据结构·算法
罗超驿11 分钟前
双指针算法经典案例:LeetCode 283. 移动零(Java详解)
java·算法·leetcode
人道领域19 分钟前
【数据结构与算法分析】二叉树面试通关手册:遍历图解 · 分类对比 · 代码模板
数据结构·算法·leetcode·深度优先
水蓝烟雨20 分钟前
2901. 最长相邻不相等子序列 II
算法·leetcode
zhouwy11320 分钟前
C++ STL标准模板库详解
c++