assembly - Cómo imprimir un flotador de precisión simple con printf
x86-64 (1)
printf(3)
especificador de formato
%f
printf(3)
quiere un
double
.
No hay forma de hacer que printf acepte un
float
, solo
double
o
long double
.
Las promociones de argumento por defecto de C
especifican que las llamadas a funciones variadas como
foo(char *fmt, ...)
promueven el
float
al
double
y realizan las promociones enteras habituales de tipos enteros estrechos a
int
, para los argumentos finales que coinciden con la
...
parte de El Prototipo.
(Lo mismo se aplica a todos los argumentos para llamar a funciones sin prototipo).
N1570 6.5.2.2 Llamadas a funciones, subsecciones 6 y 7
.
Por lo tanto, C no proporciona ninguna forma para que la persona que llama pase un
float
a
printf
, por lo que no tiene conversión, y
%f
significa
double
.
(
%lf
también funciona para el
double
, suponiendo que la implementación lo ignore para las conversiones no enteras /
wchar_t
.
Se requiere aceptar
%lf
para el
double
en
las implementaciones de
wchar_t
C99 / C11 y C ++ 11
, por lo que puede usar con seguridad el mismo formato
%lf
cadena con un
double
para
printf
y
scanf
).
Tenga en cuenta que
scanf
es diferente, ya que
float *
y
double *
no se ven afectados por esas promociones.
En este caso,
cargue con
CVTSS2SD .num, %xmm0
.
Si observa la
salida del compilador
, verá que gcc hace todo lo que hizo y
pxor
-zero el registro primero para romper la dependencia falsa del valor anterior de
%xmm0
.
(El mal diseño de
cvtss2sd
deja sin cambios los 64 bits superiores del destino). gcc erra por el lado de la precaución e inserta instrucciones de ajuste a cero para romper falsas dependencias en muchos casos.
Probablemente esté obteniendo 0 porque los bits superiores de xmm0 son cero
.
Cuando
printf
mira los 64 bits bajos de xmm0 como un
double
(binario IEEE64 en x86)
, encuentra el patrón de bits para
123.4f
en los 32 bits bajos de la mantisa, y el resto cero.
Esto representa un número muy pequeño (denormal), por lo que sale como cero con
%f
.
Puede probar el equivalente con un
float
(por ejemplo, en
http://www.h-schmidt.net/FloatConverter/IEEE754.html
), configurando algunos bits en la mitad baja para ver lo que obtiene.
Si utilizó
%g
(notación científica) o
%a
(representación hexadecimal del patrón de
double
bit), aparecerían los bits distintos de cero.
(A menos que haya habilitado el modo Denormals Are Zero en el MXCSR).
Estoy tratando de imprimir un número de coma flotante en el ensamblado x86_64 pero solo imprime el valor como cero.
Ya hay algunas preguntas sobre esto. Uno parecía resolverse asegurándose de establecer el número de registros vectoriales que está utilizando en% al . Otro mostró que necesita tener una alineación de pila de 16 bytes . Pero, estoy haciendo ambas cosas y todavía no obtengo la salida correcta.
Este es mi programa:
# prints a floating point value
.section .rodata
.fmt: .string "num: %f/n"
.num: .float 123.4
.section .text
.global main
.type main, @function
main:
subq $8, %rsp # 16-byte alignment
# print my number
movss .num, %xmm0 # load float value
movq $.fmt, %rdi # load format string
movb $1, %al # use 1 vector register
call printf
# exit
addq $8, %rsp # undo alignment
movq $0, %rax # return 0
ret