【问题标题】:swprintf() with narrow strings带有窄字符串的 swprintf()
【发布时间】:2014-05-09 19:00:53
【问题描述】:

以下代码行在 Visual Studio 2010 中产生垃圾:

swprintf(buf, L"Value is %s", "abcd");

但是,相同的代码在 Linux 上也可以正常工作。

通过试用,我可以在 Visual Studio 下使用 %S 而不是 %s 使其工作。

swprintf(buf, L"Value is %S", "abcd");

我想知道这是 Visual Studio 2010 中的错误还是我遗漏了什么。问候。

【问题讨论】:

  • 这是一个罕见的问题,可以而且应该合法地标记 C++ 和 C。
  • @Deduplicator 一些看似 C 和 C++ 通用的库函数,实际上它们之间存在一些差异。除非 OP 绝对确定两种语言的答案是相同的,并且有一个具体原因说明单个语言标记不足,否则我认为 OP 仅将其标记为 C++ 是正确的。
  • @hvd:我并不是在暗示 OP 不谨慎或错误标记,只是在这种情况下 C 也同样适用。因此,我建议添加 C。如果给您带来不同的印象,我很抱歉。

标签: c++ c visual-studio-2010 visual-c++


【解决方案1】:

这是一个“错误”,尽管该行为是设计使然。宽字符串 printf 和 scanf 函数的初始 Visual C++ 实现早于它们在 C 中的标准化,在某些情况下,其行为偏离了 C 标准库规范的要求。

在 C 标准库规范中,%s%c 格式说明符必须始终与 char 数组或元素配对,l 长度修饰符必须在 wchar_t 数组或提供了元素。

在这些函数 (documentation) 的 Visual C++ 实现中,%s%c 格式说明符需要一个相应的“自然”宽度参数。对于窄字符串 printf 和 scanf 函数,需要 char 指针或元素,对于宽字符串函数,需要 wchar_t 指针或元素。要传递“其他”宽度的字符串,可以使用%S%C 格式说明符。或者,hl 长度修饰符可用于明确指定字符串参数是窄字符串还是宽字符串。

除其他优点外,这些函数的 Visual C++ 实现使通过the _TCHAR mappings in <tchar.h> 轻松迁移旧代码以使用 Unicode 字符串成为可能。不幸的是,标准化的东西与 Visual C++ 实现中已经实现的不同(我不熟悉这里的历史;可能标准化的东西与另一个实现相匹配。)。

【讨论】:

  • UCS-2 在迁移到 UTF-16 之前; UTF-8 也是 Unicode。至少同样不幸的是,他们转向 UCS-2 而不是 UTF-8。
  • 虽然它是在那个时候发明的,但这并不能改变它是不幸的恕我直言的事实。此外,它并没有改变假装只有 UTF-16 是 unicode 至少具有误导性的事实。
【解决方案2】:

广泛的printfscanf 函数的Microsoft 实现不符合标准,因此您在Linux(符合标准)和Windows(损坏)上得到不同的结果。

The link Matt posted in his answer 指向暗示该不当行为的 MSDN 页面:

C、S 和 Z 类型字符以及 c 和 s 类型字符在与 printf 和 wprintf 函数一起使用时的行为是 Microsoft 扩展,不是ANSI 兼容。 Visual C++ 不支持 F 类型字符。

强调我的。顺便说一句:这里的 ANSI 表示所有 C 标准,并通过扩展 C++ 标准。

具体问题是 MS 重新定义了那些转换说明符 (cs) 以在与宽函数一起使用时期望 UTF-16。

【讨论】:

    【解决方案3】:

    %s 和 %S 有不同的含义:

    s:与 printf 函数一起使用时,指定单字节或多字节字符串;当与 wprintf 函数一起使用时,指定一个宽字符串。字符最多显示到第一个空字符或达到精度值。

    S:与 printf 函数一起使用时,指定一个宽字符串;与 wprintf 函数一起使用时,指定单字节或多字节字符串。字符最多显示到第一个空字符或达到精度值。

    这就是为什么

    swprintf(buf, L"Value is %S", "abcd");
    

    显示正确的值。

    MSDN 链接是here

    【讨论】:

    • 这并不能解释 OPs 的观察结果,尽管您至少得到了一半的解释。
    • 这个答案应该指出%s的这种解释不符合C99标准。
    【解决方案4】:

    "abcd" 是一个窄字符串,因为您省略了“L”。 swprintf() 期望它的所有 %s 字符串输入都是宽的。

    【讨论】:

      猜你喜欢
      • 2015-03-11
      • 2011-10-05
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 2015-12-30
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多