2009-04-24 2 views
4

Рассмотрим эту программу:stringstream неподписанное преобразование сломанной?

#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; 
} 

Я попробовал это на GCC (версия 4.0.1 Apple, Inc. построить 5490) на OS X 10.5.6 и утверждение верно; он не может преобразовать -1 в unsigned short.

В Visual Studio 2005 (и 2008), однако, утверждение терпит неудачу, и результирующее значение n совпадает с тем, что вы ожидаете от генерируемого компилятором неявного преобразования, то есть «-1» составляет 65535, «-2», это 65534 и т. д. Но тогда это становится странным на «-32769», который преобразуется в 32767.

Кто такой, а кто здесь не прав? (А что, черт возьми, происходит с -32769 ??)

+0

Вы можете проверить флаги формата по умолчанию, установленные на istringstream на Mac, используя флаги()? – dirkgently

+1

, поскольку мы, кажется, не получаем поток ответов, я опубликовал небольшую измененную версию на clC++ m - http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/97475b21515462c9 # – 2009-04-24 21:47:56

+0

Спасибо Нейлу. Боже, усложняется! Я вижу, что это не так просто, как я когда-то надеялся. –

ответ

5

поведение востребовано НКУ в Запись Max Lybbert основана на таблицах стандарта C++, которые отображают поведение iostream на преобразователях printf/scanf (или, по крайней мере, это мое чтение). Однако поведение scanf g ++, похоже, отличается от поведения 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.

+0

Этот ответ на clC++ m http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/97475b21515462c9/ce369a327fa39243#ce369a327fa39243 подтверждает, что ввод C++ задан как интермс ввода C - но приходит к совсем другому выводу! – 2009-04-25 07:14:54

+0

не уверен, что согласен с этим парнем. strtoul говорит, что полученное значение отрицается. когда 1 отрицается для unsigned short, это USHRT_MAX (по модулю арифметики), что и возвращает MSVC. Не знаете, почему он говорит, что он должен вернуться? –

+0

Нет, я думаю, он был немного вне лучи. Но как вы относитесь к первоначальному вопросу? – 2009-04-25 12:27:28

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 (который я думаю, что использование г ++) это дает:

flags: 4098 

Это говорит о том, что GCC использует другое значение по умолчанию fmtflags. Начиная с fmtflags контролируйте, какие преобразования возможны, вы получаете разные результаты.

+0

Уточнение: компиляция codepad C++ использует g ++ 4.1.2. Я думаю, что у istringstream Mac, вероятно, будет тот же самый или похожий fmtflags (но отличный от VS2005). – dirkgently

+0

Не могло ли это означать, что фактические значения реализации fmtflags различаются между реализациями C++? – 2009-04-24 18:38:22

+0

Да, может. Каково ваше влияние на источник ошибки? – dirkgently

3

Во-первых, чтение строки «-1» в качестве отрицательного числа зависит от локали (локаль может быть идентифицировать отрицательные числа, заключая их в скобки). Your default standard is the "classic" C locale:

До сих пор преобладающего использования районов неявно, в поток ввода/вывода. Каждый istream и ostream имеет свои собственные locale. Локаль потока по умолчанию является глобальным locale во время создания потока (стр. 6). ...

Первоначально глобальная локаль является стандартным языком C, locale :: classic() (стр. 11).

По словам ребят, ССАГПЗ, numeric overflow is allowed to fail the stream input operation (говорить о отрицательных чисел, которые переполненных подписанную Int):

[T] он поведение libstdC++ - v3 строго стандарт конформным. ... Когда попытка чтения выполняется, не подходит к подписанному int i, и он терпит неудачу.

Благодаря другой ответ, a bug was filed and this behavior changed:

К сожалению, по-видимому, мы никогда не корректно распознаны отрицательные значения без знака. Исправление прост. ...

Исправлено в mainline, также будет зафиксировано в 4.4.1.

Во-вторых, хотя целочисленное переполнение, как правило, предсказуемы, я считаю, что это officially undefined behavior, так что пока я не могу сказать, почему -32769" превращается в 32767, я думаю, что это разрешено.

+0

+1 для местности tidbit. – paxos1977

Смежные вопросы