【问题标题】:printf unknown specifier %Sprintf 未知说明符 %S
【发布时间】:2011-09-19 18:18:59
【问题描述】:

我正在尝试让示例代码正常工作,它使用以下几行:

   WCHAR cBuf[MAX_PATH];

    GetSharedMem(cBuf, MAX_PATH);

    printf("Child process read from shared memory: %S\n", cBuf);

获取共享内存:

__declspec(dllexport) VOID __cdecl GetSharedMem(LPWSTR lpszBuf, DWORD cchSize) 
{ 
    LPWSTR lpszTmp; 

    // Get the address of the shared memory block

    lpszTmp = (LPWSTR) lpvMem; 

    // Copy from shared memory into the caller's buffer

    while (*lpszTmp && --cchSize) 
        *lpszBuf++ = *lpszTmp++; 
    *lpszBuf = '\0'; 
}

奇怪的是,我在 printf 行上得到了一个未知的说明符错误。 %S 是 MS 扩展名,不兼容 ANSI,但我认为默认情况下会包含它。如何开启此功能?

我正在使用 microsoft visual studios,不知道如何检查我的选项

【问题讨论】:

  • 你用的是什么编译器?有什么选择?
  • @Kerrek SB:打印宽字符
  • 如果你们有兴趣,整个代码是msdn.microsoft.com/en-us/library/ms686958%28v=vs.85%29.aspx
  • 可能相关:您意识到GetSharedMem() 中存在缓冲区溢出问题?如果您设法复制MAX_PATH 字符,您将无条件地设置下一个导致溢出的字符。您可能需要更正它。

标签: c windows printf format-specifiers


【解决方案1】:

来自http://www.globalyzer.com/gzserver/help/localeSensitiveMethods/formatting.htm#larges

不合格的字符串说明符(大 %S)

这些表显示了 Windows 和 ANSI 如何根据 %S 说明符和函数调用的样式(单、通用或宽)处理参数:

Windows 函数说明符参数需要是 printf/sprintf (单个/MBCS) %S wchar_t* _tprintf/_stprintf(通用)%S(不要使用) wprintf/swprintf(宽)%S char* ANSI 函数说明符参数需要是 printf/sprintf (单个/MBCS) %S wchar_t* wprintf/swprintf(宽)%S wchar_t*

ANSI 和 Windows 在单字节或宽度方面基本上都将 %S 视为与 %s 相反,这具有讽刺意味的是,Windows 和 ANSI 再次以不同的方式处理这些说明符。

请注意,ANSI 本质上始终以与 %ls 相同的方式处理 %S,换句话说,它始终被假定为宽字符串。

另一方面,Windows 根据函数调用的类型对 %S 进行不同的处理。对于单字节函数调用,%S 的作用类似于宽 %ls 说明符,但对于宽函数调用,%S 的作用类似于单字节 %hs 说明符。

此说明符不应用于 Windows 通用调用。由于 %S 是 %s 的“对立面”,如果 _UNICODE 标志关闭,则参数需要宽,如果 _UNICODE 标志打开,则需要单字节。 TCHAR 泛型类型不能以这种方式工作,并且没有“反 TCHAR”类型的数据类型。

我在 Visual C++ 2010 中尝试了以下操作:

#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    WCHAR cBuf[MAX_PATH];
    TCHAR tBuf[MAX_PATH];

    wcsncpy_s(cBuf, L"Testing\r\n", MAX_PATH);
    _tcsncpy_s(tBuf, _T("Testing\r\n"), MAX_PATH);

    printf("%S", cBuf); // Microsoft extension
    printf("%ls", cBuf); // works in VC++ 2010
    wprintf(L"%s", cBuf); // wide
    _tprintf(_T("%s"), tBuf); // single-byte/wide

    return 0;
}

设置:

/ZI /nologo /W3 /WX- /Od /Oy- /D "WIN32" /D "_D​​EBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Yu"StdAfx.h" /Fp"Debug\TestWchar.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" / gd /analyze- /errorReport:queue

【讨论】:

  • 如何关闭 unicode 标志?现在 Windows 不接受 %ls 或 %hs
  • 您使用的是哪个版本的 Visual Studio? VC++ 2010 支持 %ls,但我不记得 VC++ 6 支持它。如果您想在早期版本中坚持使用 ANSI,您可能需要使用 wprintf 函数。
【解决方案2】:

打印宽字符串:

wchar_t * str = /*...*/

printf("The string: %ls\n", str);
// or
wprintf(L"The string: %ls\n", str);

【讨论】:

  • hmm 我似乎遇到了一个错误,说 L 修饰符只对 e,f,g 说明符有效,这是你的 printf 行
  • 那是什么编译器? %Ls 格式说明符是标准的,尽管我认为只有 C99(当引入 wchar_t 时)。等等,可能是%ls,小号l
  • @Joe:是的,确实,谢谢!经常检查手册是值得的:-)
  • 现在这很奇怪......它给了我一个错误,即 l 只对 d、i、n、o、u 和 x 说明符有效。我正在使用微软视觉工作室
  • @mugetsu:MSVC 可能没有完全或正确地实现 C99。嗯...让我检查一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2011-05-23
  • 2012-03-14
  • 2014-01-07
  • 2017-11-16
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多