【问题标题】:Outputing numbers in several data types to MessageBox creates a mess将几种数据类型的数字输出到 MessageBox 会造成混乱
【发布时间】:2020-03-30 12:39:56
【问题描述】:

我正在尝试以 MB 为单位逐行输出从 bytereal10 的几乎所有数据类型的小数(整数和浮点数),但由于某种原因,几乎没有一个可以正确显示(下图),大多数它们坏了,有人可以解释为什么会这样吗?我的错误是什么?

.386
.model flat, stdcall
option casemap: none

include \masm32\include\masm32rt.inc

.data
titletext db  'Title',0
frmt db  'A (Byte) = %d',10
     db  '-A (Byte) = %d',10
     db  'A (Word) = %d',10
     db  'B (Word) = %d',10
     db  '-A (Word) = %d',10
     db  '-B (Word) = %d',10
     db  'A (ShortInt) = %d',10
     db  'B (ShortInt) = %d',10
     db  'C (ShortInt) = %d',10
     db  '-A (ShortInt) = %d',10
     db  '-B (ShortInt) = %d',10
     db  '-C (ShortInt) = %d',10
     db  'A (LongInt) = %d',10
     db  'B (LongInt) = %d',10
     db  'C (LongInt) = %d',10
     db  '-A (LongInt) = %d',10
     db  '-B (LongInt) = %d',10
     db  '-C (LongInt) = %d',10
     db  'D (Single) = %g',10
     db  '-D (Single) = %g',10
     db  'E (Double) = %g',10
     db  '-E (Double) = %g',10
     db  'F (Extended) = %g',10
     db  '-F (Extended) = %g',0

buff db 1024 dup (?)

Abyte db 6
nAbyte db -6
Aword dw 6
Bword dw 603
nAword dw -6
nBword dw -603
Ashort dd 6
Bshort dd 603
Cshort dd 6032000
nAshort dd -6
nBshort dd -603
nCshort dd -6032000
Along dq 6
Blong dq 603
Clong dq 6032000
nAlong dq -6
nBlong dq -603
nClong dq -6032000
Dsingle real4 0.001
nDsingle real4 -0.001
Edouble real8 0.074
nEdouble real8 -0.074
Fextended real10 735.430
nFextended real10 -735.430

.code
start:
   invoke  crt_sprintf, addr buff, addr frmt,
      Abyte, nAbyte,
      Aword, Bword, nAword, nBword,
      Ashort, Bshort, Cshort, nAshort,nBshort, nCshort,
      Along, Blong, Clong, nAlong, nBlong, nClong,
      Dsingle, nDsingle,
      Edouble, nEdouble,
      Fextended, nFextended
   invoke  MessageBox, 0, addr buff, addr titletext, MB_OK
   invoke  ExitProcess, 0
end start

当前结果:

【问题讨论】:

  • 您正在使用%d 转换来转换您未提升为int 的窄参数。如果 MASM 的 invoke 没有为您神奇地对它们进行签名或零扩展,它们可能包含大量垃圾。此外,short 通常是 16 位字节,但您使用的是dd。在这种情况下,这无关紧要,因为 32 位代码总是至少使用 32 位堆栈槽来传递参数。说到这一点,看看invoke 是如何组装的,然后看看它做了什么之后的堆栈内存,看看你的 args 是否被正确传递。
  • 此外,浮点数都被破坏了,因为您忘记将浮点的 C 默认提升应用到双倍,这对于 args 总是发生在可变参数函数的 ... 部分。 How to print a single-precision float with printf。因此,您的 4 字节浮点数稍后会扭曲所有内容。
  • 哦,同样,您有一些 dq 64 位整数,但您仍然告诉 sprintf 它们是 %d int
  • @PeterCordes 谢谢!还想问一下您通常需要多少缓冲区?
  • @PeterCordes 我已将所有byteworddword 更改为签名类型并且效果很好,但我遇到了qwordreal4 的问题。我将%d 更改为%ld 为qword,但它仍然将0 放在下一个条目中,并将所有数字移到它之后。关于浮点数,正如我从您发布的另一个线程的链接中了解到的那样 - 无法打印出浮点数,我需要以某种方式将其转换为不同的类型?对不起,如果我理解不好。

标签: assembly x86 printf masm masm32


【解决方案1】:

您的格式字符串与您要传递的 invoke 不匹配。

您正在使用%d 转换来转换您未提升为int 的窄参数。 %hhd%hd 分别是 int8_t(作为整数的有符号字符)和 int16_t (short) 所需的转换。 ISO C 没有指定 short = int16_t,但在 32 位 Windows 上就是这种情况。

无论如何,如果 MASM 的 invoke 没有为您神奇地对它们进行符号或零扩展,那么用于传递这些窄整数的 4 字节堆栈槽的高字节可能包含高垃圾。

另外,short 通常是 16 位字节,但您使用的是 dd。在这种情况下,这无关紧要,因为 32 位代码始终至少使用 32 位堆栈槽来传递参数。

要自己进一步调试:看看调用指令或宏是如何实际汇编成真正的机器指令的。即反汇编生成的代码,看看它到底在做什么。 (或者使用带有反汇编视图的调试器来单步执行)。此外,在每个步骤之后、call 之前,使用调试器查看堆栈内存,以查看您的参数是否正确传递。

如果您不确定所需的正确 asm 指令序列是什么,请查看 C 或 C++ 编译器的编译器输出,以获取使用您想要的相同类型的 C 全局变量调用 sprintf 的等效代码。 (例如,在 https://godbolt.org/ 上,它有 32 位 x86 MSVC 可用。它的调用约定和类型宽度应该是 crt_sprintf 所期望的,你通过 MASM32 链接。)


此外,浮点数全部损坏,因为您忘记将 C 默认的 float 提升应用到 double,这对于 args 总是发生在可变参数函数的 ... 部分。 How to print a single-precision float with printf 所以你的 4 字节浮点数稍后会扭曲所有内容。

同样,您有一些 dq 64 位整数,但您仍然告诉 sprintf 它们是 %d (int)。所以你实际上得到了 dq 的高半部分和低半部分被两个单独的 %d 转换读取,导致错误的转换读取错误的字节。


我已将所有 byteworddword 更改为签名类型并且效果很好,但我在使用 qwordreal4 时遇到了问题。我将%d 更改为%ldqword,但它仍然将0 放在下一个条目中,并将所有数字移到它之后。

在 32 位 ABI 中,long 仍然是 32 位类型。您需要long long转换为%llddq

关于浮点数,正如我从您发布的另一个线程的链接中了解到的那样 - 无法打印出浮点数,我需要以某种方式将其转换为不同的类型?

没错。您根本不能将invokereal4 一起用于类似printf 的函数,这些函数通过C 可变参数函数的... 部分获取其arg。

查看编译器生成的等效 C 代码。

在调用之前,您必须将 real4 转换为 double 并手动推送它们。 (按从右到左的顺序调用推送,最后一个 args 最先推送,所以您可以执行这些推送,然后使用 invoke 我猜?)

还有your libc probably uses long double = double(请参阅该答案的 cmets),而不是 10 字节 x87 类型。所以可能没有办法让 sprintf 处理一个 tbyte,你还必须将它转换为 double。或者干脆不要使用real10,除非你找到可以处理它的 C 库。

(哦,是你问了这个问题。还是一样的问题。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2018-08-11
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多