为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

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


已经有一些问题了。通过确保您在%al中设置要使用的向量寄存器数,似乎可以解决该问题。另一个表明您需要16个字节的堆栈对齐。但是,我同时做这些事情,仍然没有得到正确的输出。


这是我的程序:


# 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


查看完整描述

2 回答

?
墨色风雨

printf(3)的%f格式说明符需要一个double。无法使printf接受float,仅double或long double。


C的默认参数提升指定对可变参数函数(例如,foo(char *fmt, ...)提升float为to)的调用double,并执行将窄整数类型转换int为的通常的整数提升,以匹配匹配...原型部分的尾部arg 。(这同样适用于所有不带原型的用于调用函数的arg。) N1570 6.5.2.2函数调用,第6和7小节。


因此,C无法为调用者提供将a传递float给的方法printf,因此它没有进行转换的方法,%f即meansdouble。(%lf也适用于double,假设实现在非整数/ wchar_t转换中忽略了它。 在C99 / C11和C ++ 11 实现中需要接受%lffordoubleprintf,因此可以安全地%lf将doublefor printf和for用作相同格式的字符串scanf)。


请注意,这scanf是不同的,因为float *并且double *不受这些促销的影响。


在这种情况下,请加载CVTSS2SD .num, %xmm0。

如果查看编译器的输出,您将看到gcc做了您所做的所有事情,并且pxor先将寄存器设置为-零,以打破对的旧值的错误依赖%xmm0。(cvtss2sd糟糕的设计使目标的高64位保持不变。)gcc谨慎起见,并在许多情况下插入异或归零指令以打破错误的依赖关系。


您可能会得到0,因为xmm0的高位恰好是零。当printf将xmm0的低64位看作double(x86上的IEEE binary64)时,它将找到123.4f尾数的低32位中的位模式,其余为零。这代表一个非常小的(不正常的)数字,所以用表示为零%f。


您可以尝试使用等号float(例如,在http://www.h-schmidt.net/FloatConverter/IEEE754.html上),在下半部分设置一些位以查看得到的结果。


如果使用%g(科学记数法)或%a(double位模式的十六进制表示),则会显示非零位。(除非您在MXCSR中启用了“零归零”模式。)


查看完整回答
反对 回复 2019-12-06
?
LEATH

是的,这不是显而易见的。我忘记了,但可能甚至无法float在C中将传递给var-args函数。升级规则将转换指定为double。我希望,如果可能的话,至少GNU C会有一个格式说明符。(就像%hf什么)。对我来说,我实际上只是通过查看asm来解决此限制,因为否则编译器将始终为您进行转换。(此外,实际上是因为不想打印float具有%a十六进制样式的格式

查看完整回答
反对 回复 2019-12-06
  • 2 回答
  • 0 关注
  • 52 浏览
我要回答
慕课专栏
更多

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信