为何char与short类型数据会被存储在4字节寄存器中?
为什么char/short类型数据会被存入4字节寄存器?
背景信息
- 正在学习将C代码转换为汇编代码,发现
char和short类型的数据会被存储在4字节寄存器中 - 编译参数:
-Og -g,通过gdb的disas main命令查看汇编,运行环境为64位系统
示例C代码
#include <stdio.h> int main(void) { const int LEN = 3; char c[LEN]; c[0] = 1; c[1] = 2; c[2] = 3; for(int i = 0; i < LEN; i ++) { printf("%d\n", c[i]); } return 0; }
对应部分反汇编代码
0x000000000000116e <+5>: sub $0x10,%rsp 0x0000000000001172 <+9>: mov %fs:0x28,%rax 0x000000000000117b <+18>: mov %rax,0x8(%rsp) 0x0000000000001180 <+23>: xor %eax,%eax 0x0000000000001182 <+25>: movb $0x1,0x5(%rsp) 0x0000000000001187 <+30>: movb $0x2,0x6(%rsp) 0x000000000000118c <+35>: movb $0x3,0x7(%rsp) 0x0000000000001191 <+40>: mov $0x0,%ebx 0x0000000000001196 <+45>: jmp 0x11b9 <main+80> 0x0000000000001198 <+47>: movslq %ebx,%rax # why %edx? 0x000000000000119b <+50>: movsbl 0x5(%rsp,%rax,1),%edx 0x00000000000011a0 <+55>: lea 0xe5d(%rip),%rsi # 0x2004 0x00000000000011a7 <+62>: mov $0x1,%edi 0x00000000000011ac <+67>: mov $0x0,%eax 0x00000000000011b1 <+72>: callq 0x1070 <__printf_chk@plt> 0x00000000000011b6 <+77>: add $0x1,%ebx 0x00000000000011b9 <+80>: cmp $0x2,%ebx 0x00000000000011bc <+83>: jle 0x1198 <main+47>
疑问与关联思考
了解Java中byte、char或short会被提升为int,不确定这是否与此问题相关。
解答
这一现象是C语言整数提升规则与x86-64调用约定共同作用的结果,和Java的类型提升本质逻辑一致:
C语言的整数提升规则
在表达式计算、函数参数传递等场景中,char、short(包括有符号和无符号版本)会被自动提升为int类型——只要int能够容纳原类型的所有取值(在绝大多数系统中,int是4字节,完全覆盖1字节char和2字节short的取值范围)。这一规则是为了简化不同小整数类型之间的运算逻辑,避免额外的类型转换开销。汇编层面的具体体现
- 存储阶段:从反汇编的
movb指令可以看到,char类型数据确实是以1字节的形式存储在栈上(写入0x5(%rsp)等单字节地址)。 - 读取与传递阶段:
movsbl指令的作用是将单字节的有符号char符号扩展为4字节的int,然后存入32位寄存器%edx中。这是因为printf的%d格式符期望接收int类型的参数,而按照x86-64的System V调用约定,整数参数会通过寄存器传递,%edx对应第三个参数的位置(前两个参数分别是__printf_chk的flag和格式串地址)。 - 64位系统的寄存器特性:在x86-64模式下,写入32位寄存器会自动将对应64位寄存器的高32位清零,因此
%edx中的4字节int值会被正确扩展为64位,符合调用约定的要求。
- 存储阶段:从反汇编的
与Java类型提升的关联
Java中byte、char、short提升为int的设计,本质和C的整数提升是相同的思路——使用通用的int类型作为小整数运算的默认类型,减少类型转换的复杂度和性能开销。
内容的提问来源于stack exchange,提问作者OnlyWick
相关产品推荐
相关产品推荐

