如何使用printf打印单精度浮点数

时间:2016-05-06 23:26:29

标签: assembly printf x86-64

我试图在x86_64程序集中打印浮点数,但它只是将值打印为零。

已经有一些问题。通过确保you set the number of vector registers you're using in %al,似乎解决了一个问题。另一个表明you need to have a stack alignment of 16 bytes。但是,我正在做这两件事而仍然没有得到正确的输出。

这是我的计划:

# 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

1 个答案:

答案 0 :(得分:8)

<强> printf(3)'s %f format specifier wants a double 即可。无法让printf接受float,仅doublelong double

C的默认参数提升指定对foo(char *fmt, ...)等可变函数的调用将float提升为double,并执行通常的整数提升窄整数类型到int,用于跟踪与原型的...部分匹配的args。 (这同样适用于所有没有原型调用函数的args。)N1570 6.5.2.2 Function calls, subsections 6 and 7

因此,C无法让调用者将float传递给printf,因此它没有转化,%f表示double < / strong>即可。 (%lf也适用于double,假设实现忽略了非整数/ wchar_t转换。Accepting %lf for double is required in C99/C11 and C++11 printf implementations,因此您可以安全地使用相同的%lf格式字符串,doubleprintf的{​​{1}}。

请注意,scanf不同,因为scanffloat *不受这些促销活动的影响。

在这种情况下,加载double *

如果你看compiler output,你会看到gcc做你所做的一切,CVTSS2SD .num, %xmm0 - 首先将寄存器归零以打破对{{1}的旧值的错误依赖}。 (cvtss2sd糟糕的设计会使目标的高64位保持不变。)gcc会谨慎行事,并在许多情况下插入xor-zeroing指令以打破错误依赖。

您可能会得到0,因为xmm0的高位恰好为零。当pxor将xmm0的低64位视为double (IEEE binary64 on x86)时,它会在尾数的低32位中找到%xmm0的位模式,其余为零。这代表一个非常小的(非正规)数字,因此它与printf一起显示为零。

您可以尝试使用123.4f的等效值(例如,在http://www.h-schmidt.net/FloatConverter/IEEE754.html上),在下半部分设置一些位以查看您获得的内容。

如果使用%f(科学记数法)或float%g位模式的十六进制表示),则会显示非零位。 (除非你在MXCSR中启用了Denormals Are Zero模式。)