🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录
🍉学习方向:C/C++方向
⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平
前言:本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型等等。
C++的两个参考文档:
老朋友(非官方文档):cplusplus
官方文档(同步更新):cppreference
正文 在C语言中,类型转换分为显式类型转换和隐式类型转换两种方式。C++ 也支持这些 C 风格的转换,但推荐使用更安全的 C++ 风格类型转换操作符。
具有C风格的强制类型转换:式类型转换、隐式类型转换一、隐式类型转换 (Implicit Type Conversion) 隐式类型转换,又称自动类型转换,是编译器在不需要程序员显式指定的情况下自动进行的类型转换。
常见场景: 赋值时类型不匹配
表达式中有不同类型的操作数
函数调用时实参与形参类型不匹配
代码语言:javascript复制int i = 42;
double d = i; // 隐式将int转换为double
float f = 3.14f;
double sum = f + d; // 隐式将f提升为double
void func(double x);
func(i); // 隐式将int转换为double转换规则:算术转换 (Arithmetic Conversion):1、小类型向大类型转换;
2、整型向浮点型转换;
3、有符号向无符号转换(可能导致意外结果)。
整数提升 (Integer Promotion):1、char、short 等小整型在运算时自动提升为 int。
二、显式类型转换 (Explicit Type Conversion)使用强制类型转换运算符显式指定转换。
C 风格强制转换语法:代码语言:javascript复制(type_name) expression
// 或
type_name (expression) // C++ 中可用我们举个例子:
代码语言:javascript复制double d = 3.14159;
int i = (int)d; // 显式将double转换为int,截断小数部分
float f = 1.5f;
int j = int(f); // C++风格的写法,效果相同
unsigned int u = 0xffffffff;
int k = (int)u; // 可能产生负数注意:
1、强制转换会绕过编译器的类型检查;
2、可能导致数据丢失或未定义行为;
3、指针类型转换非常危险。
代码语言:javascript复制int x = 10;
char *p = (char *)&x; // 危险:可能违反严格别名规则三、C++ 中的改进(对比)C++ 提供了四种更安全的类型转换操作符:
1、static_cast —— 用于良性转换
2、const_cast —— 去除 const 属性
3、dynamic_cast —— 用于多态类型的向下转换
4、reinterpret_cast —— 低层重新解释(最危险)
代码语言:javascript复制double d = 3.14;
int i = static_cast
尽量避免使用 C 风格的强制转换;
优先使用隐式转换(当安全时);
必须显式转换时,C++ 中优先使用 static_cast 等新式转换;
特别注意指针和整型之间的转换;
注意有符号和无符号类型之间的转换陷阱。
详解显式类型转换与隐式类型转换一、隐式类型转换隐式类型转换又称自动类型转换,是编译器在不需要程序员显式指定的情况下自动进行的类型转换。
1、常见的隐式类型转换场景(1) 算术转换 (Arithmetic Conversion)当表达式中包含不同类型的操作数时发生:
代码语言:javascript复制int i = 5;
double d = 2.5;
double result = i + d; // i被隐式转换为double(2) 赋值转换 (Assignment Conversion)当赋值运算符两侧类型不一致时:
代码语言:javascript复制int i;
double d = 3.14;
i = d; // d被隐式转换为int,小数部分被截断(3) 函数调用转换 (Function Call Conversion)实参与形参类型不匹配时:
代码语言:javascript复制void func(double x);
func(5); // int 5被隐式转换为double 5.0(4) 返回类型转换 (Return Conversion)返回类型与函数声明类型不一致时:
代码语言:javascript复制double func()
{
return 5; // int 5被隐式转换为double 5.0
}2、隐式转换的规则体系(1) 整数提升 (Integer Promotion) char、short等小整型自动提升为int
代码语言:javascript复制char c1 = 'A', c2 = 'B';
int result = c1 + c2; // char提升为int再相加(2) 寻常算术转换 (Usual Arithmetic Conversion)按以下优先级转换(低→高):
bool、char、short → int
int → unsigned int
unsigned int → long
long → unsigned long
unsigned long → long long
long long → unsigned long long
整型 → float
float → double
double → long double
(3) 有符号与无符号转换代码语言:javascript复制unsigned int u = 10;
int i = -5;
if (i < u)
{ // i被转换为unsigned int,结果可能出乎意料
// 这里可能不会执行
}3、隐式转换的风险代码语言:javascript复制int i = 300;
char c = i; // 可能溢出,结果依赖于实现二、显式类型转换 显式类型转换是程序员明确指定的类型转换,也称为强制类型转换。
1、C风格的显式转换语法:
代码语言:javascript复制(type_name) expression
// 或
type_name (expression) // C++风格(1) 基本类型转换代码语言:javascript复制double d = 3.14159;
int i = (int)d; // 截断小数部分,i=3(2) 指针类型转换代码语言:javascript复制int x = 10;
char *p = (char *)&x; // 重新解释内存(3) 函数指针转换代码语言:javascript复制void (*func_ptr)() = (void (*)())some_function;2、C++风格的显式转换 C++提供了四种更安全的转换操作符——
(1) static_cast用于良性转换,编译时检查:
代码语言:javascript复制double d = 3.14;
int i = static_cast
代码语言:javascript复制const int ci = 10;
int *pi = const_cast
代码语言:javascript复制Base* b = new Derived();
Derived* d = dynamic_cast
代码语言:javascript复制int i = 10;
float f = reinterpret_cast
int i = (int)d; // i=3,小数部分丢失(2) 指针误用代码语言:javascript复制int x = 0x12345678;
char *p = (char *)&x;
if (*p == 0x78)
{
// 依赖于字节序
// 在小端机器上成立
}(3) 类型双关 (Type Punning)代码语言:javascript复制float f = 3.14f;
unsigned u = *(unsigned *)&f; // 违反严格别名规则三、实践方面的建议 优先使用隐式转换:当转换安全且意图明显时
慎用显式转换:特别是指针和引用类型的转换
C++推荐使用新式转换:比C风格转换更安全
注意数值范围:确保目标类型能容纳转换后的值
避免类型双关:使用union或memcpy替代危险指针转换
使用static_assert检查:C++11起可用
代码语言:javascript复制static_assert(sizeof(int) == 4, "int must be 4 bytes");四、典型面试问题1、以下代码的输出是什么?
代码语言:javascript复制unsigned int u = 10;
int i = -5;
if (i < u)
{
printf("True");
}
else
{
printf("False");
}答案:可能输出"False"(因 i 被转换为很大的unsigned值)。
2、如何安全地将float的位模式转换为int?
代码语言:javascript复制float f = 3.14f;
int i;
memcpy(&i, &f, sizeof(f)); // 安全方式结尾往期回顾:
由于往期回顾的博客太多了,这里就只放前一篇博客的链接啦——
【C/C++】深入详解内置类型和自定义类型
关于C++的四种强制转换类型,大家可以去看这位大佬的博客,比较易懂——
【C++】深度解析C++的四种强制转换类型(小白一看就懂!!)
往期回顾(本文涉及的一些往期博客)
C风格的强制类型转换:
【C/C++】初识C++(三):C++入门内容收尾——const引用,指针和引用关系梳理,inline(内联函数),nullptr替代NULL
C语言中的强制类型转换:
变量的一些知识点整理(续)、算术操作符、赋值操作符:=和复合赋值、单目操作符以及强制类型转换的知识点总结
结语:本文内容到这里就全部结束了。本文博主带大家回顾了介绍C语言时就登场,一直到现在都有不少戏份的强制类型转换,C++中具有C风格的强制类型转换:显式类型转换、隐式类型转换。