4

I'm trying to get a wchar_t* formatted with an int as a parameter. I've Googled a lot but I've only ended up more confused. So, consider this code:

int main(int argc, char** argv) {

   wchar_t buf[16];
   wsprintf(buf, L"%d", 5);
   wprintf(L"[%ls]\n", buf);

   system("pause");
   return 0;

};

Having assumed that wchar_t, wsprintf and wprintf are the wide character equivalents of char, sprintf and printf respectively, I expected the above to print [5], but it prints garbage between [ and ]. What is the correct way to achieve the desired result? And what am I misunderstanding here?

(I should clarify that portability is more important than security here, so I'd like to know a solution that uses this family of functions instead of safer vendor-specific extensions.)

Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • How do you know it's printing garbage? Have you piped the output into a file and looked at it in a hex editor? – Kerrek SB Jan 05 '13 at 14:54
  • No. I've assumed that `wprintf` would just print it to the console in the expected way. Is that incorrect somehow? – Theodoros Chatzigiannakis Jan 05 '13 at 15:02
  • 1
    For me (Mac OS X 10.7.5), `wsprintf()` is unavailable, however `swprintf()` prints out `[5]` as expected. –  Jan 05 '13 at 15:21
  • Perhaps then you should change your question to "What is the correct assumption I should hold about this code?" – Kerrek SB Jan 05 '13 at 15:22
  • @H2CO3 Thank you! It seems that I had misunderstood the naming convention for these functions. `wsprintf` is Windows specific, while `swprintf` is the actual wide character equivalent of `sprintf`. Would you care to make that comment an answer so I can mark it as accepted? – Theodoros Chatzigiannakis Jan 05 '13 at 15:32
  • @TheodorosChatzigiannakis Of course! I'll do it right now. Edit: done, thanks! –  Jan 05 '13 at 15:43

3 Answers3

7

wsprintf() is a Windows-specific function, it's unavailable on Unixes. What you want to achieve can be done in a more portable way (I have tried this slightly modified code snippet and it worked as expected):

#include <wchar.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    wchar_t buf[16];
    swprintf(buf, sizeof(buf) / sizeof(*buf), L"%d", 5);
    wprintf(L"[%ls]\n", buf);

    return 0;
}

Output:

[5]
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
4

wsprintf() is one of Microsoft's hybrid functions. It has a different signature depending on whether or not _UNICODE is defined during preprocessing. (What's happening under the hood, is there's an #ifdef that replaces wsprintf with wsprintfA or wsprintfW based on the nonexistence or existence of that symbol.)

If _UNICODE is defined, it expects the buffer to be of wchar_t[].

If _UNICODE is not defined (usually the default), it expects the buffer to be char[]. That's what's happening here. If you had warnings on, it would probably show a warning about incompatible pointer types. The garbage is because the 8-bit ascii that it's storing in buf is being interpreted as Unicode by wprintf().

AnotherParker
  • 789
  • 5
  • 16
1

It appears to me that you're using an incorrect format specifier for your output. I would suspect you would want

wprintf(L"[%s]\n", buf);

%ls looks like an invalid combination of specifiers - l for a "long int" size prefix on the s "string" type specifier. Documentation I've found on wprintf indicates that it treats the 's' type specifier as pointing to a wide character string (at least for MS Visual Studio).

Ryan
  • 185
  • 11
  • 2
    `%ls` and `%hs` are valid [MSVC format specifiers](http://msdn.microsoft.com/en-us/library/windows/desktop/ms647550(v=vs.85).aspx) for wide and "narrow" character strings. Using plain `%s` is a little more subtle. – DCoder Jan 05 '13 at 15:46