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