News:

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

Confused with wsprintf

Started by bf2, November 03, 2011, 04:47:32 PM

Previous topic - Next topic

bf2

The file masm32\m32lib\dw2a.asm has the following prototype of wsprintf:

wsprintfA PROTO C :DWORD,:VARARG

Windows.inc on the other hand has the prototype:

wsprintfA PROTO C :VARARG

Finally, MSDN has the definition:

int __cdecl wsprintf(
  __out  LPTSTR lpOut,
  __in   LPCTSTR lpFmt,
  __in    ...
);


Question 1a. Which of the above is correct? I am sure the answer is 'all of them', but how?

Question 1b. Regarding the '... [in]' bit, MSDN says the following:
"One or more optional arguments. The number and type of argument parameters depend on the corresponding format-control specifications in the lpFmt parameter."
What on earth might that mean? Can anyone provide an example?

Question 2: How do the following calls work? How does wsprintf work out what parameter is at what possition?
Example 1: MASM

invoke wsprintf, lpBuffer, ADDR formatString, dwValue


Example 2: C

wsprintf (szBuffer, "The sum of %i and %i is %i", 5, 4, 5 + 4);


In other words, in the first case we are passing the format string as a separate parameter, while in the second it's included in the second parameter !

Thanks as always.

qWord

formal correct:
wsprintfA proto c :LPTSTR, :LPCTSTR, args:VARARG
:bg
However, because of VARAGR, the other definitions will also work (as long as passing the buffer and the format-string)
FPU in a trice: SmplMath
It's that simple!

qWord

Quote from: bf2 on November 03, 2011, 04:47:32 PMWhat on earth might that mean? Can anyone provide an example?

Question 2: How do the following calls work? How does wsprintf work out what parameter is at what possition?

Quote"The sum of %i and %i is %i", 5, 4, 5 + 4
FPU in a trice: SmplMath
It's that simple!

bf2

Quote from: qWord on November 03, 2011, 05:16:45 PM
Quote from: bf2 on November 03, 2011, 04:47:32 PMWhat on earth might that mean? Can anyone provide an example?

Question 2: How do the following calls work? How does wsprintf work out what parameter is at what possition?

Quote"The sum of %i and %i is %i", 5, 4, 5 + 4

I understand that, but how does that fit with the prototype? And how can in another call we can pass th format string as an entirely separate parameter?

qWord

Quote from: bf2 on November 03, 2011, 05:28:17 PMI understand that, but how does that fit with the prototype? And how can in another call we can pass th format string as an entirely separate parameter?
Beacause the created code is the same for all variations -> you can declare each c-function with VARARG as long as  using the right number of parameters when calling the function (the types must also match).

Calling conventions (pdf)
FPU in a trice: SmplMath
It's that simple!

NoCforMe

My take on this--and I really don't want to confuse things further with wrong information, so please correct me if I'm wrong---is that the MSDN definition is the best one. wsprintf() takes 2 mandatory arguments (the output buffer and the format string), and a variable number of arguments (0-n) after that.

I don't understand why the windows.inc file only lists the variable-argument list: isn't that incorrect? Seems to me that the prototype should have at least 2 DWORDs followed by the VARARG. Why is that?

bf2

Quote from: NoCforMe on November 03, 2011, 07:00:15 PM
My take on this--and I really don't want to confuse things further with wrong information, so please correct me if I'm wrong---is that the MSDN definition is the best one. wsprintf() takes 2 mandatory arguments (the output buffer and the format string), and a variable number of arguments (0-n) after that.

I don't understand why the windows.inc file only lists the variable-argument list: isn't that incorrect? Seems to me that the prototype should have at least 2 DWORDs followed by the VARARG. Why is that?

NoCforMe, you are right that things are very confusing (well for me anyway). For example even if we take the MSDN definition to be the correct one, how then can a C call like the below work?
wsprintf (szBuffer, "The sum of %i and %i is %i", 5, 4, 5 + 4);
Because as per the MSDN definition, the format string must be the second parameter passed, whereas the call passes an arbitrary string with the format string embedded in it.

Edit. OK, I got that bit. The MSDN description says about the second parameter:
"    [in] Pointer to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string."
So the second parameter can be an arbitrary string containing the format string, or just the format string.

jj2007

Here is a little testbed. Attached the disassembly.
The point here is that TestOnePlusVar and TestVarArg behave identically, unless you insist to call TestOnePlusVar without any args.

include \masm32\include\masm32rt.inc

TestFix PROTO :DWORD, :DWORD
TestFixC PROTO C :DWORD, :DWORD
TestOnePlusVar PROTO C :DWORD, :VARARG
TestVarArg PROTO C :VARARG

.code
start: inkey "bye"
exit
invoke TestFix, 1, 2
invoke TestFixC, 1, 2
; invoke TestOnePlusVar ; error A2137:too few arguments to INVOKE
invoke TestVarArg
invoke TestOnePlusVar, 1
invoke TestVarArg, 1
invoke TestOnePlusVar, 1, 2, 3
invoke TestVarArg, 1, 2, 3

TestFix proc v1, v2
  mov eax, v1
  mov ecx, v2
  ret
TestFix endp

TestFixC proc C v1, v2
  mov eax, v1
  mov ecx, v2
  ret
TestFixC endp

TestOnePlusVar proc C v1, v2:VARARG
  mov eax, v1
  mov ecx, v2
  ret
TestOnePlusVar endp

TestVarArg proc C v1:VARARG
  mov eax, v1
  ret
TestVarArg endp

end start

NoCforMe

Quote from: bf2 on November 03, 2011, 07:30:31 PM
Edit. OK, I got that bit. The MSDN description says about the second parameter:
"    [in] Pointer to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string."
So the second parameter can be an arbitrary string containing the format string, or just the format string.

Wellll ... the second argument is always the format string (dunno what you mean by "arbitrary" there).

Forget MASM, or assembly language in general: this all stems from the classic C definition of xxprintf(). The "format" string is just that: a string that controls the formatting of the output. In what mathematicians would call the "degenerate case", the format string itself can be the output, as in



wsprintf (&buffer, "This is all she wrote");



(here the number of variable args is zero) Does that make sense?

(To put this another way, the number of arguments after the two required ones depends on the content of the formatting string, where each replacement field found (%(something)) requires a parameter to fill that field.)

In any case, two arguments are definitely required by this function, so I still am confused as to the windows.inc prototype, despite jj's attempt at elucidation.

bf2

Quote from: NoCforMe on November 03, 2011, 09:16:32 PM
Quote from: bf2 on November 03, 2011, 07:30:31 PM
Edit. OK, I got that bit. The MSDN description says about the second parameter:
"    [in] Pointer to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string."
So the second parameter can be an arbitrary string containing the format string, or just the format string.

Wellll ... the second argument is always the format string (dunno what you mean by "arbitrary" there).


Ignore me. I got myself confused by the example where the second parameter is a string like "The number is %ld" as opposed to just "%ld".
I am easily confused.

NoCforMe

Don't worry, you ain't the only one. Join the club.

Hey, you know what's a great antidote to your confusion? Write your own version of wsprintf().

Seriously. I don't mean a full-blown implementation, with all the bells and whistles and formats. I wrote my own version of printf() (back in my 16-bit coding days) that handles the following data types:

  • %u (unsigned integer)
  • %d (signed integer)
  • %x (hexadecimal)
  • %s (ASCIIZ string)
It's actually not all that hard, and is a good programming exercise. If you do it, you'll really "get" the whole format string business.