帅气咕杂货间

C++ wcout的奇妙问题

Word count: 465 / Reading time: 2 min
2019/11/02 Share

问题阐述

3A9948DBCAE1D0D3D09E8D70E47E7598

14E430F4F12B1283F053419A31FA83D1

72B1700E9D0D8872F6AA6A5E347AB452

大概就是

1
2
wchat_t s[3] = {'a','b','c'};
wcout<<s;

会导致之后的其他输出都不会被输出

问题排查

这样的问题当然要从源码下手了

首先查看其对应的<<重载函数

image

可以看到其调用了__put_character_sequence()函数,传入了os、str和length(str)

继续深入

image

貌似在函数开头是对传入参数进行param check的代码,出于直觉(偷懒),直接对if结果进行断点调试。

果不其然,原代码

1
2
3
4
5
6
7
8
if (__pad_and_output(_Ip(__os),
__str,
(__os.flags() & ios_base::adjustfield) == ios_base::left ?
__str + __len :
__str,
__str + __len,
__os,
__os.fill()).failed())

会因为if判断为false而执行代码

1
__os.setstate(ios_base::badbit | ios_base::failbit);

而__pad_and_output()函数逻辑为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
ostreambuf_iterator<_CharT, _Traits>
__pad_and_output(ostreambuf_iterator<_CharT, _Traits> __s,
const _CharT* __ob, const _CharT* __op, const _CharT* __oe,
ios_base& __iob, _CharT __fl)
{
if (__s.__sbuf_ == nullptr)
return __s;
streamsize __sz = __oe - __ob;
streamsize __ns = __iob.width();
if (__ns > __sz)
__ns -= __sz;
else
__ns = 0;
streamsize __np = __op - __ob;
if (__np > 0)
{
if (__s.__sbuf_->sputn(__ob, __np) != __np)
{
__s.__sbuf_ = nullptr;
return __s;
}
}
if (__ns > 0)
{
basic_string<_CharT, _Traits> __sp(__ns, __fl);
if (__s.__sbuf_->sputn(__sp.data(), __ns) != __ns)
{
__s.__sbuf_ = nullptr;
return __s;
}
}
__np = __oe - __op;
if (__np > 0)
{
if (__s.__sbuf_->sputn(__op, __np) != __np)
{
__s.__sbuf_ = nullptr;
return __s;
}
}
__iob.width(0);
return __s;
}

猜测变量ob 为ouput begin 变量op为output position 变量oe为output end

调试发生,在代码段

1
2
3
4
5
6
7
8
9
__np = __oe - __op;
if (__np > 0)
{
if (__s.__sbuf_->sputn(__op, __np) != __np)
{
__s.__sbuf_ = nullptr;
return __s;
}
}

因为__np>0且__s.__sbuf_->sputn(__op, __np) != __np

导致__s.__sbuf_ = nullptr;

并返回结果.failed()

时间原因有待继续深究

个人猜测为发现输入结尾没有\0导致param check失败

同时__os.setstate(ios_base::badbit | ios_base::failbit);后,wcout将无法继续输出。

需要wcout.clean()清除错误状态

CATALOG
  1. 1. 问题阐述
  2. 2. 问题排查