Is there a format specifier that always means char string with _tprintf?
Asked Answered
K

4

8

When you build an app on Windows using TCHAR support, %s in _tprintf() means char * string for Ansi builds and wchar_t * for Unicode builds while %S means the reverse.

But are there any format specifiers that always mean char * string no matter if it's an Ansi or Unicode build? Since even on Windows UTF-16 is not really used for files or networking it turns out to still be fairly often that you'll want to deal with byte-based strings regardless of the native character type you compile your app as.

Kilohertz answered 14/4, 2011 at 20:20 Comment(0)
W
7

The h modifier forces both %s and %S to char*, and the l modifier forces both to wchar_t*, ie: %hs, %hS, %ls, and %lS.

Whop answered 14/4, 2011 at 22:1 Comment(5)
Is this specific to MSVC? I just noticed this warning from gcc on Ubuntu 10: warning: use of ‘h’ length modifier with ‘s’ type characterKilohertz
No, it is not specific to MSVC, some other compilers support the h and l modifiers for the s type as well. I guess gcc is not one of them.Whop
I have just tried this with gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 -- it works, sort of.Pride
According to this interesting page, %hs is not a valid modifier in general and is considered insecure. I know that it works for MSVC with and without unicode, but clang generates a [-Wformat] warning, complaining that "length modifier 'h' results in undefined behavior or no effect with 's' conversion".Puttee
Again, it appears to be compiler specific. Some compilers support it (BCC, VC++), some do not (GCC).Whop
P
1

This might also solve your problem:

_TCHAR *message;
_tprintf(_T("\n>>>>>> %d") TEXT(" message is:%s\n"),4,message);
Petticoat answered 20/4, 2012 at 5:27 Comment(0)
B
0

You can easily write something like this:

#ifdef _UNICODE
#define PF_ASCIISTR    "%S"L
#define PF_UNICODESTR  "%s"L
#else
#define PF_ASCIISTR    "%s"
#define PF_UNICODESTR  "%S"
#endif

and then you use the PF_ASCIISTR or the PF_UNICODESTR macros in your format string, exploiting the C automatic string literals concatenation:

_tprintf(_T("There are %d ") PF_ASCIISTR _T(" over the table"), 10, "pens");
Bootie answered 14/4, 2011 at 20:26 Comment(0)
V
0

I found, that '_vsntprintf_s' uses '%s' for type TCHAR and works for both, GCC and MSVC. So you could wrap it like:

int myprintf(const TCHAR* lpszFormat, va_list argptr) {
    int len = _vsctprintf(lpszFormat, argptr); // -1:err
    if (len<=0) {return len;}
    auto* pT = new TCHAR[2 + size_t(len)];
    _vsntprintf_s(pT, (2+len)*sizeof(TCHAR), 1+len, lpszFormat, argptr);
    int rv = printf("%ls", pT);
    delete[] pT;
    return rv;
}
int myprintf(const TCHAR* lpszFormat, ...) {
    va_list argptr;
    va_start(argptr, lpszFormat);
    int rv = myprintf(lpszFormat, argptr);
    va_end(argptr);
    return rv;
}



int main(int, char**) { return myprintf(_T("%s"), _T("Test")); }
Virgulate answered 15/5, 2019 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.