News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

wsprintf

Started by cork, July 20, 2010, 09:07:32 AM

Previous topic - Next topic

cork

I've included a MASM32 source file, below, with an example.

I'm using 64-bit Windows Vista and MASM32 to assemble.

I pass a QWORD to wsprintf using the '%lu' format specifier. Instead of translating the entire 64-bit unsigned integer into an ASCII string, it translates only the low 32-bits, altogether ignoring the high 32-bits.

In the example below the ASCII string that wsprintf returns is "3" (just the low 32-bits). It should return "4294967299".

I've spent the past hour trying to suss out the issue. Any insights into what kind of bonehead assumption I've made that isn't correct?


.486                          ; For 80486 CPUs or higher.
.model flat, stdcall        ; Windows is always the 32-bit FLAT model
option casemap:none    ; Use case-sensitive labels.

include    \masm32\include\windows.inc       ; always first
include    \masm32\include\kernel32.inc     
includelib \masm32\lib\kernel32.lib
include    \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.data

MsgTitle       db  '64-bit Unsigned', 0
MsgText       db  '                                                ', 0
blah            dq  4294967299   ; [addr]=low dword=03H, [addr+4]=high dword=01H
lu_format     db  '%lu', 0

.code

Test1:
    invoke wsprintf, addr MsgText, OFFSET lu_format, blah
    invoke  MessageBox, 0, ADDR MsgText, ADDR MsgTitle, MB_OK or MB_ICONINFORMATION
exit_Test1:
    invoke ExitProcess, 0
    ret
end Test1

MichaelW

The wsprintf function apparently does not support 64-bit integers. You can use the CRT sprintf function instead (build this example as a console app).

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      msgtext   db 20 dup(0)
      i64       dq 1234567887654321h
      format    db "%I64x", 0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke crt_sprintf, ADDR msgtext, ADDR format, i64
    print ADDR msgtext,"h",13,10,13,10

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

cork

Maybe %u and %lu are equivalent specifiers, both meaning an unsigned 32-bit integer.

That must be the case.

I guess if I'm going to translate a 64-bit unsigned integer to a string I have to do it myself, as it doesn't look wsprintf() supports it.


MichaelW

I'm fairly certain that wsprintf was, at least originally, based on the CRT sprintf function. For C (32-bit, not the old 16-bit versions) int and long int are both 32-bit integers, so the "l" (long) modifier specifies a 32-bit integer and "%u" and "%lu" are effectively the same. To specify a 64-bit integer you would need to use "ll" (long long), except for the Microsoft C's where you would need to use "I64", but note that wsprintf apparently supports neither. And since it also does not support floating-point values, I basically see no reason to use wsprintf for anything.
eschew obfuscation

MichaelW

According to this, "Starting with Windows XP, wsprintf and wvsprintf support the I64|I modifiers."
eschew obfuscation

cork

Quote from: MichaelW on July 20, 2010, 10:57:06 AM
According to this, "Starting with Windows XP, wsprintf and wvsprintf support the I64|I modifiers."

Thank you very much Michael. That works perfectly.

'%I64d' for signed 64-bit integers
'%I64u' for unsigned 64-bit integers

Great!