libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
10.22k stars 1.87k forks source link

testautomation_stdlib.c does use "%s" for formating wchar_t* strings #9220

Closed madebr closed 5 months ago

madebr commented 9 months ago

When building the tests in c++ mode, mingw complains because "%s" is used as format string for wchar_t strings. here https://github.com/libsdl-org/SDL/blob/790cd395f54f458303fb3b4a4f8ed4fd62719e55/test/testautomation_stdlib.c#L377-L384

MinGW suggests to use %hs instead of %s, but Google tells me to use %ls instead.

All testautomation_stdlib.c wchar_t-related warnings ``` /home/maarten/projects/SDL/test/testautomation_stdlib.c: In function 'stdlib_swprintf': /home/maarten/projects/SDL/test/testautomation_stdlib.c:384:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 384 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:384:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 384 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:390:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 390 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:390:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 390 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:400:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 400 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:400:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 400 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:407:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 407 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:407:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 407 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:415:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 415 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:415:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 415 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:423:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 423 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:423:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 423 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:431:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 431 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:431:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 431 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:439:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 439 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:439:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 439 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:447:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 447 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:447:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 447 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:455:82: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 455 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:455:91: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 455 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: %s, got: %s", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:463:83: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 463 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:463:94: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 463 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:471:83: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 471 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:471:94: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 471 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:478:83: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 478 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:478:94: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 478 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:508:91: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 508 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:508:102: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 508 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:516:91: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 516 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:516:102: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 516 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:526:83: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'const wchar_t *' {aka 'const short unsigned int *'} [-Wformat=] 526 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~~~~~ | | | | char * const wchar_t * {aka const short unsigned int *} | %hs /home/maarten/projects/SDL/test/testautomation_stdlib.c:526:94: warning: format '%s' expects argument of type 'char *', but argument 4 has type 'wchar_t *' {aka 'short unsigned int *'} [-Wformat=] 526 | SDLTest_AssertCheck(SDL_wcscmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text); | ~^ ~~~~ | | | | char * wchar_t * {aka short unsigned int *} | %hs ```
sezero commented 9 months ago

MinGW suggests to use %hs instead of %s, but Google tells me to use %ls instead.

Depends on what the linked C library actually supports (msvcrt.dll, ucrt, msvcrXX.dll, whatever..)

slouken commented 9 months ago

Ah, I usually use %S, but I don't know if that's standard. This should definitely be fixed though, either way.

madebr commented 9 months ago

I think the choices are:

sezero commented 9 months ago
* `%hs` on MinGW, for compatibility with Windows (gcc has `-fshort-wchar` for this) (`sizeof(wchar_t) == 2`)
* `%S` on MSVC (`sizeof(wchar_t) == 2`)

This part I don't understand: Why is there a difference here between MinGW and MSVC? Does MinGW provide some kind of special treatment in printing of wchar_t strings? I think not: it is handled by the same library linked to residing on the Windows system: %whatever is interpreted by that C library. Otherwise what am I missing here?

madebr commented 8 months ago

I might have been wrong. Building the source below gives consistent behavior between platforms when using %S.

#include <stddef.h>
#include <stdio.h>
int main() {
  const wchar_t txt[] = L"Hello world!";
  printf("%d S: %15S hs: %15hs ls: %15ls\n", sizeof(wchar_t), txt, txt, txt);
  return 0;
}
$ gcc a.c && ./a.out && i686-w64-mingw32-gcc a.c && wine a.exe && x86_64-w64-mingw32-gcc a.c && wine a.exe
4 S:    Hello world! hs:               H ls:    Hello world!
2 S:    Hello world! hs:               H ls:    Hello world!
2 S:    Hello world! hs:               H ls:    Hello world!

I don't know what %hs is used for.

sezero commented 8 months ago

. Building the source below gives consistent behavior between platforms when using %S.

That's good, we should use %S for it, then.

I wonder whether old msvcrt.dll (e.g. the one in winxp) supports it..

sezero commented 5 months ago

Should this one be closed now after https://github.com/libsdl-org/SDL/commit/1938d25b7ec90f6fe45aa59bd696fbc31643c584 ?

slouken commented 5 months ago

Yep!