我在修这在Linux和Windows,并在某些情况下,都应该包含格式化的内容缓冲区是比内容更小运行的遗留代码。
该代码使用的swprintf其中根据documentation
大小 - 高达大小 - 1个字可以写,加空终止
确实会截断字符串,但在尝试它coliru我遇到了意想不到的结果:
#include <iostream>
#include <string>
#include <cwchar>
int main()
{
wchar_t wide[5];
std::swprintf(wide, sizeof wide/sizeof *wide, L"%ls", L"111111111");
std::wcout << wide;
}
将导致1111??
但
#include <iostream>
#include <string>
#include <cwchar>
int main()
{
wchar_t wide[20];
std::swprintf(wide, sizeof wide/sizeof *wide, L"%ls", L"111111111");
std::wcout << wide;
}
工作得很好。
怎么了 ?
附:我希望我能一切更改为C ++流/字符串,但我不能,wchar_t
阵列的各个角落。
TL;博士:对于某种原因,这些空终止语义依赖于函数调用成功,并为swprintf
如果缓冲区足够大,它才能成功。因此,在您第一次尝试的阵列是不是空终止。
这是潜移默化的,但swprintf
不像snprintf
。它不“最多N-1个字符”编写,并认为成功的在所有情况下。
下面是相同的文件说,有关从swprintf
返回值:
返回值:如果写宽字符(不包括终止空宽字符)数是否发生编码错误或如果将要产生的字符数等于或大于尺寸(包括当大小为零)成功或负值
而且,事实上,your attempt returns -1。
从这个(从注意,报价下),我们能够确定swprintf
考虑操作是否有未在所提供的输出缓冲足够的字节失败。它不会溢出该缓冲区,但它也可能无法完成其工作,其工作包括编写一个NULL终止符。如果没有NULL终止符,你是wchar_t*
[有效]传递给std::wcout
将运行出界,你的程序未定义的行为。
我承认,这,在休闲阅读,似乎矛盾围绕size
参数的语义,为此,C11规定:
不超过
n
宽字符更被写入,包括终止空宽字符,它总是被添加(unlessn
是零)。
......没有说明在函数调用是否成功,否则任何条件。
有可能是要求在标准这个社论缺陷,或执行错误的范围。但是,即使没有是真的,你的函数调用被认为是不成功的,而且我不认为你应该相应地依靠胜负。
我们至少可以看到的libc意图以上破败,从this manual page on Formatted Output Functions匹配:
返回值是给定的输入生成的字符的数量,不包括尾部零。如果不是所有的输出适合提供的缓冲区返回负值。你应该有一个更大的输出字符串再试一次。注:这是从的snprintf如何处理这种情况的不同。
你将不得不听从上述说明:
而窄串提供的std ::的snprintf,这使得能够确定所需的输出缓冲器大小,没有等效为宽字符串,并以确定的缓冲器大小,该程序可能需要调用的std ::的swprintf,检查结果值,并重新分配一个更大的缓冲区,再次尝试,直到成功。
......或者完全切换到一些其他的功能。