NO

Author Topic: StringCbPrintf weirdness  (Read 176 times)

Offline algernon_77

  • Member
  • *
  • Posts: 10
StringCbPrintf weirdness
« on: August 21, 2020, 07:57:27 am »
Quite frankly, don't know if this is a bug or it's just me.. tried to run something like

Code: [Select]
TCHAR   buf[64];
TCHAR   msg1[] = TEXT("msg1");
TCHAR   msg2[] = TEXT("msg2");

StringCbPrintf ( buf, ARRAYSIZE(buf), TEXT("%s %s"), msg1, msg2 );

..and if I define UNICODE I get:

warning #2234: Argument 4 to 'StringCbPrintfW' does not match the format string; expected 'char *' but found 'wchar_t *'.
warning #2234: Argument 5 to 'StringCbPrintfW' does not match the format string; expected 'char *' but found 'wchar_t *'.

Trying to print buf (with a MessageBox), it seems as if StringCbPrintfA is called instead (only the first byte from each string is printed, because being a widechar, the other is 0).

I have Pelle 10.
I don't have any more ideas :)

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 1765
Re: StringCbPrintf weirdness
« Reply #1 on: August 21, 2020, 10:19:14 am »
This isn't a bug.
The printf() specifier "%s", not like MS compiler, requires the long flag for unicode strings "%ls". This behavior is due to strict compliance to the standard of PellesC compiler (notoriously the MS compiler isn't compliant at all...  ::)).
So if you compile as ascii there are no errors, but if you compile for UNICODE you'l get the error.
There are 2 possible solutions, first if you add the long specifier will correct the error, but it will come out again compiling without UNICODE, the second is to automatically modify the specifier depending on the compilation. I.E:
Code: [Select]
#if defined(UNICODE) || defined(_UNICODE)
#define STR_SPEC "ls"
#else
#define STR_SPEC "s"
#endif
 ....
    TCHAR   buf[64];
    TCHAR   msg1[] = TEXT("msg1");
    TCHAR   msg2[] = TEXT("msg2");

    StringCbPrintf ( buf, ARRAYSIZE(buf), TEXT("%") TEXT(STR_SPEC) TEXT(" %") TEXT(STR_SPEC), msg1, msg2 );

Offline algernon_77

  • Member
  • *
  • Posts: 10
Re: StringCbPrintf weirdness
« Reply #2 on: August 21, 2020, 03:54:40 pm »
Yes, that's it  :)  :)
Thanks a lot!

I peered so much inside strsafe.h that my eyes hurt, lol. But it payed off in the end, I found a few errors (I think):

- inside StringGetsWorkerW, line 120, *pszDest = '\0'; should be *pszDest = L'\0'; ?
- inside _StringExHandleOtherFlagsA, line 463, *pszDestEnd = L'\0'; should be *pszDestEnd = '\0'; ?
- inside StringCchPrintfW, line 1061, *pszDest = '\0'; should be *pszDest = L'\0'; ?
- inside StringCbVPrintfW, line 2038, *pszDest = '\0'; should be *pszDest = L'\0'; ?

Thanks again!

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 1765
Re: StringCbPrintf weirdness
« Reply #3 on: August 21, 2020, 04:12:35 pm »
Yes, that's it  :)  :)
Thanks a lot!

I peered so much inside strsafe.h that my eyes hurt, lol. But it payed off in the end, I found a few errors (I think):

- inside StringGetsWorkerW, line 120, *pszDest = '\0'; should be *pszDest = L'\0'; ?
- inside _StringExHandleOtherFlagsA, line 463, *pszDestEnd = L'\0'; should be *pszDestEnd = '\0'; ?
- inside StringCchPrintfW, line 1061, *pszDest = '\0'; should be *pszDest = L'\0'; ?
- inside StringCbVPrintfW, line 2038, *pszDest = '\0'; should be *pszDest = L'\0'; ?

Thanks again!
You're welcome.
Strictly speaking yes it would be better to prefix wide chars constants with the 'L' prefix, but in the specific case, value==0, is irrelevant because the char value is converted to 16bits wide char signed int with the same value. In C any value==0 is considered equivalent.
« Last Edit: August 21, 2020, 04:14:38 pm by frankie »

Offline algernon_77

  • Member
  • *
  • Posts: 10
Re: StringCbPrintf weirdness
« Reply #4 on: August 21, 2020, 05:12:29 pm »
Aha, I see now. I was under the impression that if you assign '\0' to a widechar, only one byte would get the value.
Regards!

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 1765
Re: StringCbPrintf weirdness
« Reply #5 on: August 22, 2020, 02:39:19 pm »
Aha, I see now. I was under the impression that if you assign '\0' to a widechar, only one byte would get the value.
Regards!
In C a `char` is itself an `int`, generally 8 bits wide on almost all systems, while a 'wide char' is again an `int` 16bits wide.
When you assign a `char` to a `wchar` the compiler converts the 'char' integer to a 'wchar' integer.