Существует ли спецификатор формата, который всегда означает строку символа с _tprintf?

#windows #printf #tchar #format-specifiers

#Windows #printf #tchar #спецификаторы формата

Вопрос:

Когда вы создаете приложение в Windows с использованием TCHAR поддержки, %s in _tprintf() означает char * строку для сборок Ansi и wchar_t * для сборок Unicode, а %S означает обратное.

Но существуют ли какие-либо спецификаторы формата, которые всегда означают char * строку, независимо от того, является ли это сборка Ansi или Unicode? Поскольку даже в Windows UTF-16 на самом деле не используется для файлов или сетей, оказывается, что все еще довольно часто вам захочется иметь дело со строками на основе байтов, независимо от собственного типа символов, с которым вы компилируете свое приложение.

Ответ №1:

h Модификатор принудительно переводит оба %s и %S в char* , а l модификатор принудительно переводит оба в wchar_t* , т.е. %hs , %hS %ls и %lS .

Комментарии:

1. Это специфично для MSVC? Я только что заметил это предупреждение от gcc в Ubuntu 10: warning: use of ‘h’ length modifier with ‘s’ type character

2. Нет, это не специфично для MSVC, некоторые другие компиляторы также поддерживают модификаторы h и l для s типа. Я думаю, gcc не является одним из них.

3. Я только что попробовал это с gcc (Ubuntu / Linaro 4.5.2-8ubuntu4) 4.5.2 — вроде как работает.

4. Согласно этой интересной странице , %hs вообще не является допустимым модификатором и считается небезопасным. Я знаю, что это работает для MSVC с юникодом и без него, но clang генерирует предупреждение [-Wformat], в котором жалуется, что «модификатор длины ‘h’ приводит к неопределенному поведению или никакому эффекту при преобразовании ‘s'».

5. Опять же, похоже, это зависит от компилятора. Некоторые компиляторы поддерживают его (BCC, VC ), некоторые нет (GCC).

Ответ №2:

Это также может решить вашу проблему:

 _TCHAR *message;
_tprintf(_T("n>>>>>> %d") TEXT(" message is:%sn"),4,message);
  

Ответ №3:

Вы можете легко написать что-то вроде этого:

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

и затем вы используете PF_ASCIISTR или PF_UNICODESTR макросы в вашей строке формата, используя автоматическую конкатенацию строковых литералов C:

 _tprintf(_T("There are %d ") PF_ASCIISTR _T(" over the table"), 10, "pens");
  

Ответ №4:

Я обнаружил, что ‘_vsntprintf_s’ использует ‘%s’ для типа TCHAR и работает как для GCC, так и для MSVC. Таким образом, вы могли бы обернуть это как:

 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")); }