Вывод чисел в нескольких типах данных в MessageBox создает беспорядок - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь выводить десятичные дроби (int и float) почти во всех типах данных от byte до real10 построчно в МБ, но по некоторым причинам почти ни один из них не отображается правильно (изображение ниже), большинство из они сломаны, может кто-нибудь объяснить, почему это происходит и в чем моя ошибка?

.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

текущий результат:

current result

1 Ответ

0 голосов
/ 31 марта 2020

Ваша строка формата не соответствует тому, что вы получаете invoke для передачи.

Вы используете %d преобразование для узких аргументов, которые вам не подходят повышение до int. %hhd и %hd - это, соответственно, необходимые преобразования для int8_t (целое число со знаком) и int16_t (short). ISO C не указывает, что short = int16_t, но это относится к 32-битным Windows.

В любом случае, старшие байты этих 4-байтовых слотов стека для передачи этих узких целых чисел могут содержит большое количество мусора, если MASM invoke магически не подписывает или не расширяет их нулями.

Кроме того, short обычно является 16-битным байтом, но вы используете dd. Это не должно иметь значения в этом случае, так как 32-битный код всегда использует как минимум 32-битные слоты стека для передачи аргументов.

Для дальнейшей отладки самостоятельно: Посмотрите, как это вызывается директива или макрос на самом деле собирается в настоящие машинные инструкции. т.е. разобрать полученный код, чтобы увидеть, что он на самом деле делает. (Или используйте отладчик с видом разборки в один шаг). Также используйте отладчик для просмотра стековой памяти после каждого шага, перед call, чтобы проверить, правильно ли передаются ваши аргументы.

Если вы не уверены, что правильно Последовательность необходимых вам asm-инструкций: посмотрите на вывод компилятора из C или C ++ компилятора, чтобы найти эквивалентный код, который вызывает sprintf с C глобальными переменными того же типа, что и вы. (Например, для https://godbolt.org/, в котором доступно 32-разрядное x86 MSV C. Его соглашение о вызовах и ширина типов должны соответствовать тем, которые crt_sprintf ожидает, что вы связываете через MASM32.)


Кроме того, все поплавки разбиты, потому что вы забыли применить продвижение по умолчанию C для поплавка, чтобы удвоить , что всегда происходит для аргументов в части ... переменной c функция. Как напечатать число с плавающей запятой одинарной точности с помощью printf Таким образом, ваши 4-байтовые числа пересекают все позже.

И, аналогично, у вас есть dq 64-битные целые числа, но вы все равно говоря sprintf они %d (int). Таким образом, вы на самом деле получаете верхнюю и нижнюю половины dq, считываемые двумя отдельными %d преобразованиями, что приводит к неправильному преобразованию, читающему неправильные байты.


Я изменил все byte, word и dword для подписанных типов, и это работало хорошо, но у меня проблемы с qword и real4. Я изменил %d для %ld для qword, но он по-прежнему помещает 0 в следующую запись, сдвигая все числа после нее.

В 32-битных ABI long по-прежнему 32-битный тип. Вам нужно long long и преобразование для этого %lld для dq.

А насчет поплавков, как я понял из ссылки на другую ветку, которую вы разместили - невозможно распечатать поплавок, мне нужно как-то преобразовать его в другой тип?

Это правильно. Вы просто не можете использовать invoke с real4 для функций, похожих на printf, которые получают свои аргументы через ... часть функции C variadi c.

Посмотрите на компилятор сгенерированный код для эквивалентного C.

. Вам придется преобразовать ваши real4 в double и pu sh их вручную, прежде чем вызывать. (Вызывает нажатия в порядке справа налево, последние аргументы нажимаются первыми, поэтому вы можете сделать эти нажатия и затем использовать invoke Я полагаю?)

Также ваша библиотека c, вероятно, использует long double = double (см. Комментарии к этому ответу), а не 10-байтовый тип x87. Так что, вероятно, нет способа заставить этот sprintf обрабатывать тбайт, и вам придется также преобразовать его в double. Или просто не потрудитесь использовать real10, если вы не найдете библиотеку C, которая может с этим справиться.

(О, это вы задали этот вопрос. Это все та же проблема.)

...