Функция типа unsigned int возвращает отрицательное число

Вау, я думал, что знаю свой C ++, но это странно

Эта функция возвращает беззнаковое int, поэтому я подумал, что это означает, что я никогда не получу отрицательное число, верно?

Функция определяет, на сколько часов вы опережаете или отстаете от UTC. Так что для меня я нахожусь в Австралии, Сиднее, поэтому я +10 GMT, что означает, что я UTC = LocalTime + (-10). Следовательно, GetTimeZoneInformation правильно определяет, что я -10.

НО моя функция возвращает беззнаковое int, поэтому разве она не должна возвращать 10, а не -10?

unsigned int getTimeZoneBias()
{
    TIME_ZONE_INFORMATION tzInfo;
    DWORD res  = GetTimeZoneInformation( &tzInfo );

    if ( res == TIME_ZONE_ID_INVALID )
    {
        return (INT_MAX/2); 
    }

    return (unsigned int(tzInfo.Bias / 60));  // convert from minutes to hours         
}

TCHAR ch[200];
_stprintf( ch, _T("A: %d\n"), getTimeZoneBias()); // this prints out A: -10
debugLog += _T("Bias: ") + tstring(ch) + _T("\r\n");

person user593747    schedule 01.10.2011    source источник
comment
Отчасти проблема заключается в том, что для печати без знака требуется %u, в этом случае это дубликат этого вопроса, но здесь гораздо больше проблем с преобразованием типов int и unsigned.   -  person user202729    schedule 19.10.2018


Ответы (4)


Вот что, я думаю, происходит:

Фактическое значение tzInfo.Bias равно -10. (0xFFFFFFF6) В большинстве систем приведение целого числа со знаком к целому числу без знака того же размера не влияет на представление.

Таким образом, функция по-прежнему возвращает 0xFFFFFFF6.

Но когда вы распечатываете его, вы распечатываете его как целое число со знаком. Итак, он prints-10. Если вы напечатали его как целое число без знака, вы, вероятно, получите 4294967286.

Вероятно, вы пытаетесь получить абсолютное значение разницы во времени. Итак, вы хотите преобразовать это -10 в 10. В котором вы должны вернуть abs(tzInfo.Bias / 60).

person Mysticial    schedule 01.10.2011
comment
Спасибо, я получал 4294967286, который меня сбивал с толку. Мне действительно нужно переосмыслить, когда я пишу простые функции! - person user593747; 01.10.2011

Вы пытаетесь напечатать unsigned int как signed int. Измените %d на %u

_stprintf( ch, _T("A: %u\n"), getTimeZoneBias());
                       ^

Проблема в том, что целые числа сами по себе не являются положительными или отрицательными для большинства компьютеров. Дело в том, как они интерпретируются.

Таким образом, большое целое число может быть неотличимо от маленького (абсолютного значения) отрицательного.

person cnicutar    schedule 01.10.2011
comment
Скажем, nxxxx, где x - это бит 0 или 1, а n - либо -, либо +. Если вы представляете числа со знаком и без знака, тогда у вас может быть 10000 для отрицательного нуля и 00000 для положительного нуля и 10000! = 00000. Когда вы выполняете сложение, 01111 + 00001 = 10000. Вы получаете странные переносы. Комплимент такой, но цифры перевернуты. 5 - это 0101, а отрицательное 5 - это 1010. Вы все еще сталкиваетесь со странной проблемой 0 vs -0, которая в некоторых случаях действует как инверсия или -1 или +1. Два комплимента - это один комплимент, но +1. Итак, 5 - это 0101, а отрицательное 5 - это 1010 + 1 = 1011. Это волшебным образом избавляет от странной проблемы с 0 и -0. - person user2262111; 12.12.2019
comment
Если вы хотите узнать больше из моего другого комментария, см. Двоичный код: плюсы и минусы (почему мы используем два дополнения) - Computerphile от Computerphile на YouTube. youtube.com/watch?v=lKTsv6iVxV4 - person user2262111; 12.12.2019

Одна ошибка в вашем _T звонке. Должен быть:

_T("A: %u\n")

Функция действительно возвращает неотрицательное целое число. Однако, используя неправильный спецификатор printf, вы заставляете его выскакивать из стека как целое число. Другими словами, биты интерпретируются неправильно. Я считаю, что это тоже неопределенное поведение.

person Matthew Flaschen    schedule 01.10.2011
comment
Да, но разве функция getTimeZoneBias () ВСЕГДА не возвращает положительное число, так что мне не нужно беспокоиться о форматировании, потому что оно всегда будет положительным числом ?? - person user593747; 01.10.2011
comment
@Matthew Flaschen Это не неопределенное поведение, оно определяется реализацией. - person cnicutar; 01.10.2011
comment
Это положительное число, вы просто неверно интерпретируете его как отрицательное число. Вы приказываете компилятору неверно истолковать его, сообщая ему, что это число со знаком, когда это число без знака. - person David Schwartz; 01.10.2011
comment
@ user593747: Нет. Формат "%u" ожидает аргумент типа unsigned int; "%d" ожидает аргумент типа int. Объект unsigned int всегда неотрицательный (не обязательно положительный; это может быть 0), но если вы сделаете вид, что это int, он легко может оказаться отрицательным. Например, если int составляет 32 бита, тогда значение unsigned int 4294967295 имеет то же представление, что и значение int -1. - person Keith Thompson; 01.10.2011
comment
@cnicutar: У вас есть ссылка на ваше утверждение? - person CB Bailey; 01.10.2011
comment
@Charles Bailey Для C99 я думаю, что это решено 6.3.1.3/3. Мне нечего сказать о C ++ - person cnicutar; 01.10.2011
comment
@cnicutar: я не верю, что 6.3.1.3/3 - это вся история, а как насчет аргумента @JerryCoffin: stackoverflow.com/questions/5851524/. Поскольку (unsigned int)-10 слишком велик, чтобы быть представленным как int на архитектуре с двумя дополнениями, я бы подумал, что поведение не определено. - person CB Bailey; 01.10.2011

Как отмечали другие люди, когда вы приводите к unsigned int, вы фактически говорите компилятору использовать шаблон битов в int и использовать его как unsigned int. Если на вашем компьютере, как и в большинстве случаев, используется дополнение до двух, то ваш номер будет интерпретироваться как UINT_MAX-10 вместо 10, как вы ожидали. Когда вы используете описатель формата %d, компилятор возвращается к использованию того же битового шаблона, что и int вместо unsigned int. Вот почему вы все еще получаете -10.

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

person murgatroid99    schedule 01.10.2011
comment
небезопасно ли делать эти предположения (полагаться на то, что компьютер является дополнением до двух?) при написании кода? - person paIncrease; 15.03.2013
comment
Я не уверен, что вы имеете в виду. Наиболее часто используемые языки используют дополнение 2, но это почти никогда не имеет значения при написании кода. В основном он определяет крайние случаи и то, как битовые операции влияют на числа. Если вы не уверены и хотите знать, всегда проверяйте. - person murgatroid99; 15.03.2013
comment
что-то вроде вашего C-кода всегда должно быть аппаратно-независимым. Или, возможно, пословица не зависит от компилятора. Я расскажу об альтернативах дополнения 2 и ответвлениях в компиляторах. Спасибо! - person paIncrease; 25.03.2013