考虑这个程序:
#include <iostream>
#include <string>
#include <sstream>
#include <cassert>
int main()
{
std::istringstream stream( "-1" );
unsigned short n = 0;
stream >> n;
assert( stream.fail() && n == 0 );
std::cout << "can't convert -1 to unsigned short" << std::endl;
return 0;
}
我在OS X 10.5.6上的gcc(版本4.0.1 Apple Inc. build 5490)上试过这个,断言是真的;它无法将-1转换为无符号短文。
然而,在Visual Studio 2005(和2008)中,断言失败,结果n的值与编译器生成的隐式转换的结果相同 - 即“-1”为65535,“ - 2”为65534等等但是它在“-32769”处变得奇怪,转换为32767。
谁是对的,谁在这里错了? (那到底是什么-32769?)
答案 0 :(得分:5)
GCC在Max Lybbert的帖子中声称的行为是基于C ++标准的表格,它将iostream行为映射到printf / scanf转换器(或者至少是那个;我的阅读)。但是,g ++的scanf行为似乎与istream行为不同:
#include <iostream>
#include <cstdio>
using namespace std;;
int main()
{
unsigned short n = 0;
if ( ! sscanf( "-1", "%hu", &n ) ) {
cout << "conversion failed\n";
}
else {
cout << n << endl;
}
}
实际打印65535。
答案 1 :(得分:3)
首先,读取字符串“-1”作为负数取决于区域设置(区域设置可以通过将它们括在括号中来识别负数)。 Your default standard is the "classic" C locale:
到目前为止, locales 的主要用途是在流I / O中隐式使用。每个 istream 和 ostream 都有自己的区域设置。默认情况下,流的区域设置是创建流时的全局区域设置(第6页)。 ...
最初,全局语言环境是标准C语言环境, locale :: classic()(第11页)。
根据海湾合作委员会成员的说法,numeric overflow is allowed to fail the stream input operation(谈论溢出签名国际组织的负数):
<击>
[T] libstdc ++的行为 - v3严格符合标准。 ...当尝试读取时,它不适合签名的int i,并且失败。
感谢另一个答案,a bug was filed and this behavior changed:
糟糕,显然我们从未正确解析无符号的负值。该 修复很简单。 ...
在主线中固定,也将在4.4.1中修复。
其次,尽管整数溢出通常是可预测的,但我相信它是officially undefined behavior,所以虽然我不能说为什么-32769“转换为32767,但我认为这是允许的。”/ / p>
答案 2 :(得分:1)
试试这段代码:
#include <iostream>
#include <string>
#include <sstream>
#include <cassert>
int main()
{
std::istringstream stream( "-1" );
std::cout << "flags: " << (unsigned long)stream.flags() << std::endl;
return 0;
}
我在VS2005上试过这个:
flags: 513
和codepad.org(我认为使用g ++)这给出了:
flags: 4098
这告诉我gcc使用不同的默认fmtflags
。由于fmtflags
控制了哪些转换可能会产生不同的结果。