x86_64架构下用scanf读取float值时寄存器未正确接收数据
x86_64汇编中scanf读取浮点数失败的问题解决
在x86_64架构下编写汇编代码时,尝试用scanf读取float类型数值,使用了格式说明符%f但输入无法正确传入寄存器处理,相关代码如下:
section .data formato_entrada: dq "%f %f", 0 formato_saida2: dq "%f", 10, 0 formato_saida: db "%s", 0 msg_coordenadas_ponto_1: db "Digite as coordenadas do primeiro ponto (x,y): ", 0 msg_coordenadas_ponto_2: db "Digite as coordenadas do segundo ponto (x,y): ", 0 msg_coordenadas_ponto_3: db "Digite as coordenadas do terceiro ponto (x,y): ", 0 msg_distancia_1: db "Primeira distância: %.2f", 10, 0 msg_distancia_2: db "Segunda distância: %.2f", 10, 0 msg_distancia_3: db "Terceira distância: %.2f", 10, 0 msg_equilatero: db "O triângulo é equilátero.", 10, 0 msg_isosceles: db "O triângulo é isósceles.", 10, 0 msg_escaleno: db "O triângulo é escaleno.", 10, 0 section .bss x1: resq 1 y1: resq 1 x2: resq 1 y2: resq 1 x3: resq 1 y3: resq 1 distancia1: resq 1 distancia2: resq 1 distancia3: resq 1 section .text extern printf extern scanf extern sqrt extern round global main main: push rbp mov rbp, rsp ; 读取第一个点的坐标 xor eax, eax lea rdi, [msg_coordenadas_ponto_1] call printf xor eax, eax lea rdi, [formato_entrada] lea rsi, [x1] lea rdx, [y1] call scanf ; 读取第二个点的坐标 xor eax, eax lea rdi, [msg_coordenadas_ponto_2] call printf xor eax, eax lea rdi, [formato_entrada] lea rsi, [x2] lea rdx, [y2] call scanf ; 读取第三个点的坐标 xor eax, eax lea rdi, [msg_coordenadas_ponto_3] call printf xor eax, eax lea rdi, [formato_entrada] lea rsi, [x3] lea rdx, [y3] call scanf
错误原因分析
- 格式说明符与内存分配不匹配:C标准中,
scanf的%f格式说明符要求对应float类型的指针(指向4字节内存),但代码中x1、y1等变量用resq 1分配了8字节内存(对应double类型),类型不匹配导致数据写入错误。 - 字符串定义不规范:
formato_entrada用dq定义字符串,dq是8字节双字定义,适合存储64位数值,而字符串是字节序列,应该用db定义,否则可能因对齐或长度问题引发异常。
解决方法
方案一:使用float类型(4字节)
- 修改.bss段的内存分配,将
resq 1改为resd 1(分配4字节,对应float):
section .bss x1: resd 1 y1: resd 1 x2: resd 1 y2: resd 1 x3: resd 1 y3: resd 1 distancia1: resd 1 distancia2: resd 1 distancia3: resd 1
- 保持格式说明符
%f不变,同时修正字符串定义为db:
formato_entrada: db "%f %f", 0
- 后续处理浮点数时,使用
movss指令将内存中的float值加载到XMM寄存器(如movss xmm0, [x1])。
方案二:改用double类型(推荐,更适配x86_64浮点数处理)
- 保持.bss段的
resq 1(8字节,对应double)不变; - 修改格式说明符为
%lf(scanf中%lf对应double类型指针),同时修正字符串定义:
formato_entrada: db "%lf %lf", 0
- 后续处理时,使用
movsd指令加载double值到XMM寄存器(如movsd xmm0, [x1])。
额外注意:调用scanf时,xor eax, eax的设置是正确的——在x86_64 System V调用约定中,eax用于指定通过SSE寄存器传递的浮点数参数数量,这里传递的是指针(通用寄存器传递),因此eax设为0是合规的。
内容的提问来源于stack exchange,提问作者Destoper
相关产品推荐
相关产品推荐

