C/C++中的数据类型转换()/static

您所在的位置:网站首页 c语言中如何转换类型 C/C++中的数据类型转换()/static

C/C++中的数据类型转换()/static

2024-07-08 06:44| 来源: 网络整理| 查看: 265

文章目录 前言数据类型自动转换C语言中的强制类型转换C++中的强制类型转换static_castdynamic_castconst_castreinterpret_cast强转关键字的选择 总结

前言

C/C++属于静态语言,也就是在编译时变量的数据类型即可确定的强类型语言。当不同的数据类型在一起运算或者相互赋值的时候,就需要进行数据类型转换。不同数据类型占用的内存空间不同,而各种数据类型的转换时有规则的,一种通用的规则就是“小转大”自动进行,“大转小”需要强制执行。这里的“大”和“小”指的是数据范围。

为什么会有数据范围大小的区别呢?这就和饭店里的盘子一样,不同的菜肴通常使用不同的盘子,盘子有大有小,如果把小盘子里的菜装到大盘子里没有问题,但是把大盘子里的菜放到小盘子中就会溢出来,假设都使用大盘子就不会产生溢出的问题,但是这样会产生空间的浪费。而C/C++中不同类型的变量占用的内存空间不同与这些盘子非常相似,当范围小的变量赋值给范围大的变量时没有问题,但是反过来也会出现溢出。

数据类型自动转换

当不同类型的变量同时运算时就会发生数据类型的自动转换,以常见的 char、short、int、long、float、double 这些类型为例,如果 char 和 int 两个类型的变量相加时,就会把 char 先转换成 int 再进行加法运算,如果是 int 和 double 类型的变量相乘就会把 int 转换成 double 再进行运算。

自动转换的行为如下图所示,方向是从左往右自动进行:

char unsigned/int short unsigned/long double float C语言中的强制类型转换

前面说了自动转换,从这里开始聊聊强制类型转换,需要强制类型转换往往程序不那么智能了,需要人工进行干预。比如把一个int 类型的变量赋值给 char 类型的变量,或者说把两个 int 相乘时可能会得到一个很大的数,所以需要先把 int 强制转换成 double 计算防止溢出。

强制类型转换的格式为:(new_type_name) expression,其中 new_type_name 为新类型名称,expression为表达式。例如:

int val = 65535; char ch = (char)val;

或者

int m = 2147483647, n = 100; double result = (double)m * n;

无论是自动的类型转换还是强制类型转换,都只是为了本次操作或运算而进行的临时转换,转换的结果也会保存到临时的内存空间内,不会改变数据本来的类型或者具体的值。

有些强制类型转换是对原有数据的重新解释,比如:

void test(void* p) { char* buffer = (char*)p; // ... }

void* 类型的变量p,经过强制类型转换以后变成了char类型的指针,此后就可以把这段内存空间当成字符数组来处理了。

C++中的强制类型转换

在C++语言中新增了四个用于强制类型转换的关键字,分别是 static_cast、 dynamic_cast, const_cast、 和 reinterpret_cast,使用语法为 xxxx_cast(expression)。

相比于C语言中使用小括号()来完成强制类型转换,C++中这几个关键字的引入能更清晰的表明它要完成强制类型转换的意图,容易暴露出隐藏的问题。

其实很长一段时间以来,我对于这四种强转方式区分的不是很清晰,其中 const_cast 的功能还比较容易辨别,但是另外3种经常混作一团,所以才有了这篇总结,而仔细学习后才发现,这4种强转关键字的区别就在他们的名字上,下面逐个来看一下。

static_cast

这个关键字的作用主要表现在 static 上,是一种静态的转换,在编译期就能确定的转换,可以完成C语言中的强制类型转换中的大部分工作,但需要注意的是,它不能转换掉表达式的 const、volitale 或者 __unaligned 属性。

它主要有以下几种用法:

用于基本数据类型之间的转换,如把int转换成char,把int转换成double等。 int val = 110119; char c = static_cast(val); double d = static_cast(val); 将表达式转换成void类型,并将转换后的结果丢弃 int val = 110119; static_cast(val); 可以用于void* 和其他指针类类型之间的转换,但是不能用于两个无关指针类型的直接转换 // 正常转换 int *p = new int; void* p1 = static_cast(p); char* p2 = static_cast(p1); // 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’ char* p3 = static_cast(p); 可以用于类继承结构中基类和派生类之间指针或引用的转换,向上转型安全,向下转型由于没有动态类型检查,是不安全的。 struct B { }; struct D : B { }; D d; B& rb = d; D& rd = static_cast(rb); 如果涉及左值到右值、数组到指针或函数到指针的转换,也可以通过static_cast显式执行。 template inline typename std::remove_reference::type&& move(_Tp&& __t) { return static_cast(__t); } dynamic_cast

从名字上看,这个关键字与 static_cast 的静态转换是对立的,这是一个“动态”转换函数,只能对指针和引用的进行转换,并且只用于类继承结构中基类和派生类之间指针或引用的转换,可以进行向上、向下,或者横向的转换。

相比于 static_cast 的编译时转换, dynamic_cast 的转换还会在运行时进行类型检查,转换的条件也比较苛刻,必须有继承关系的类之间才能转换,并且在基类中有虚函数才可以,有一种特殊的情况就是可以把类指针转换成 void* 类型。

关于使用中的常见问题,参考以下几种情况:

普通类型的指针无法转换 int val = 100; int *p = &val; // 编译失败 //error: cannot dynamic_cast ‘p’ (of type ‘int*’) to type ‘char*’ (target is not pointer or reference to class) char* pc = dynamic_cast(p); 继承结构中基类里面没有虚函数无法转换 struct B { }; struct D : B { }; D d; B* pb = &d; // 编译失败 //error: cannot dynamic_cast ‘pb’ (of type ‘struct test1()::B*’) to type ‘struct test1()::D*’ (source type is not polymorphic) D* pd = dynamic_cast(pb) 指针或引用转换的类型不是正确的类型,如果参数类型是指针会返回目标类型空指针,如果参数类型是引用则会抛出 std::bad_cast 异常。 struct B { virtual void test() {} }; struct D : B { }; B d; B* pb = &d; D* pd = dynamic_cast(pb); // 编译成功,但是pb指针指向的类型是 B,向下转型失败,输出结果是0,也就是空指针 std::cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3