IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 为什么char+char为int类型 C/C++类型提升 -> 正文阅读

[C++知识库]为什么char+char为int类型 C/C++类型提升

最近在看模板元编程的时候遇到这么一件事: char +(or -) char => int short +(or -) short =>int 为什么两个短整型相加减的类型是一个int呢?

这里涉及到一个概念 叫做类型提升,那什么是类型提升,为什么要进行类型提升,于是我展开了实验。
我的代码如下:

template <typename T1, typename T2>
struct plus_result {
    using type = 
        decltype(std::declval<T1>() + std::declval<T2>());
};

template <typename T1, typename T2>
using plus_result_t = plus_result<T1, T2>::type;

int main() {
    plus_result_t<char, char> a;
    plus_result_t<char, short> b;
    plus_result_t<short, short> c;
    
    std::cout << typeid(a).name() << std::endl;
    std::cout << typeid(b).name() << std::endl;
    std::cout << typeid(c).name() << std::endl;
    return {};
}

输出:

    i
    i
    i

下面是x86-64 gcc 12.2生成的汇编

看一下下面一段代码,结果会是多少:

char b = 100;
char c = 200;
auto i = b + c;         
printf("%s\n", typeid(i).name());   // what is type of i?
printf("%d\n", i);                  // what is value of i?
printf("%d", sizeof i);             // how long is i ?

输出结果为:

i
44
4

x86_64指令集masm汇编如下:

 mov    BYTE PTR [rbp-0x1],0x64     ;0x64
 mov    BYTE PTR [rbp-0x2],0x64     ;0xc8
 movsx  edx,BYTE PTR [rbp-0x1]
 movsx  eax,BYTE PTR [rbp-0x2]
 add    eax,edx
 mov    DWORD PTR [rbp-0x8],eax

将十六进制立即有符号数100(0x64 -> 0110 0100) 放入[b]所指向的对象b的内存的第1个字节
将十六进制立即有符号数200(== -56, -56是有符号数,计算机中以其补码存放(1100 1000 == c8)) 放入[c]所指向的对象c的内存的第1个字节

从b中取出一字节放到32位dx寄存器edx中,同样从c中取出1字节放到32位ax寄存器eax中
这里使用movsx(带符号扩展指令),当计算机中存放一个带符号数时,符号位位于最高位。对于正数而言,会把寄存器中扩展后高位置为0,其效果和movzx(零扩展指令)一样。而对于负数,高位会被全部置为1。
因此寄存器edx为0000 0000, 0000 0000, 0000 0000, 0110 0100 -> 0x00000064; eax中数据不再为1101 0110,而是1111 1111, 1111 1111, 1111 1111, 1100 1000 -> 0xFFFFFFC8 加和为 1(舍弃), 0000002c

加和后寄存器eax中值为0x0000002c,取其双字(4字节)放到对象i中,i为44

生成汇编,i是一个4字节

为什么会生成这样的汇编呢?

C99/C11标准之常用算术转换一章:
If the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

自动类型转换的基本规则:

  1. 在表达式中,char 和 short 类型的值,无论有符号还是无符号,都会自动转换成 int 或者 unsigned int(如果 short 的大小和 int 一样,unsigned short 的表示范围就大于 int,在这种情况下,unsigned short 被转换成 unsigned int)。因为它们被转换成表示范围更大的类型,故而把这种转换称为“升级(promotion)”。

  2. 按照从高到低的顺序给各种数据类型分等级,依次为:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。这里有一个小小的例外,如果 long 和 int 大小相同,则 unsigned int 的等级应位于 long 之上。char 和 short 并没有出现于这个等级列表,是因为它们应该已经被升级成了 int 或者 unsigned int。

  3. 在任何涉及两种数据类型的操作中,它们之间等级较低的类型会被转换成等级较高的类型。

  4. 在赋值语句中,= 右边的值在赋予 = 左边的变量之前,首先要将右边的值的数据类型转换成左边变量的类型。也就是说,左边变量是什么数据类型,右边的值就要转换成什么数据类型的值。这个过程可 能导致右边的值的类型升级,也可能导致其类型降级(demotion)。所谓“降级”,是指等级较高的类型被转换成等级较低的类型。

而且现在32位或者64位CPU一次处理32位或64位数据,对于低于其的数据访问意义不大。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:22:12  更:2022-10-08 20:26:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:17:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码