当前位置: 首页 > news >正文

【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) { //近似相等 }
http://www.jsqmd.com/news/624762/

相关文章:

  • 通义千问1.5-1.8B-Chat-GPTQ-Int4入门实操:STM32开发基础概念问答
  • Pretext:值得关注的文本排版引擎皆
  • Rust的#[inline(always)]强制内联属性与编译器优化决策的覆盖
  • Waydroid终极加速指南:10倍速度部署Linux上的Android容器
  • 软件竞争管理中的差异化策略
  • Anolis OS 8.6公有云仓库源配置与常见故障排查指南
  • DsHidMini:Windows平台下的虚拟HID驱动架构解析
  • SpaceNet 6 MSAW数据集解析:多传感器融合在建筑足迹提取中的创新应用
  • Java的java.lang.foreign
  • 作业2:六位数码管显示
  • LangGraph本地开发避坑指南:从`langgraph dev`启动到`LangGraph Studio`可视化调试的全流程实战
  • Mem Reduct终极指南:一键解决Windows内存卡顿的完整教程
  • PyTorch 2.8镜像效果展示:RTX 4090D运行Marigold生成3D深度图精度对比
  • Pixel Aurora Engine 角色原画设计:游戏开发中的概念图高效产出
  • BBDown进阶指南:解锁B站视频下载的高效技巧与隐藏功能
  • 告别Keil!用CLion+WSL2搭建STM32开发环境(FreeRTOS调试实战)
  • SBTI人格测试:27种魔性人格,你是哪一种
  • 软件竞赛中的题目设计与评审标准
  • 终极指南:如何免费获取专业级Source Han Serif CN开源字体
  • SAP BTP新手避坑指南:从零开始创建Directory和Subaccount(附新加坡区选型建议)
  • MedGemma X-Ray效果展示:结构化胸片报告生成实录
  • 前端开发必备:键盘事件中的keyCode使用指南与常见问题解决
  • Go语言的竞态检测器与内存模型验证工具在并发调试中的帮助
  • Halcon22.11+Win10+RTX3060深度学习环境配置:从CUDA到cuDNN的完整指南
  • YOLOv8单图推理实战:从模型加载到结果可视化的完整流程解析
  • ORA-41002报错解析:未指定目标实例的故障修复与远程处理技巧,Oracle数据库知识分享
  • 告别依赖泥潭:Poetry 如何重塑 Python 项目生命周期管理
  • Rust的#[repr(C)]联合体布局与位字段在硬件寄存器映射中的精确控制
  • 如何在Windows上实现PDF文档处理:Poppler完整工具包终极指南
  • 训练-微调-部署全链路对齐断崖式失效分析(2023–2024真实故障库TOP10)