【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)
{
    //近似相等
}
相关推荐
赤生云电竞10 小时前
GPU算力共享平台架构实践:任务分发与资源隔离的关键配置
算法·架构·gpu算力
小七在进步10 小时前
string的使用(2)
c++
青少儿编程课堂11 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
Zwawa12 小时前
嵌入式OLED表驱动菜单:用一张表、一个栈和一个窗口重写表驱动菜单
c语言·单片机·嵌入式
wo_jack13 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
Oneshot13 小时前
DLX(Dancing Links)算法详解:求解数独最快的算法
算法
青少儿编程课堂14 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
kongdong14 小时前
Hikyuu | RSI均值回归交易策略实现
算法·均值算法·回归·量化交易·交易策略·hikyuu
小王C语言14 小时前
优选算法:分治-归并排序
算法
草莓熊Lotso14 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试