2015-08-13 3 views
-1

Вместо получения номера «2147483648» я получаю «-2147483648» из-за подписанного переполнения int. Я попробовал объявить переменную как длинную int, так и unsigned int без использования. Они просто не признаются в качестве таких типов. Если кто-то задается вопросом, я оставил значение.Программа не распознает переменную как long int или unsigned int

int multiplier = 1,i; 
long int mpy = 0; 
for(i=32;i>=0;i--){ 
mpy = 1 << multiplier++; 
printf("mpy = %d\n",mpy); 
} 
+4

Просьба представить полный, минимальный и поддающийся проверке пример. –

+0

как долго длится? – user3528438

+0

Я сделал Даниил, хотя вам просто нужно было его зацикливать до тех пор, пока он не переполнится как подписанный int – Maxitj

ответ

4

Поскольку постоянная 1 является int, при смещении влево она остается int. Если вы хотите unsigned long long, сделать это такое:

unsigned long long mpy = 1ULL << multiplier++; 

Вы можете использовать один из суффиксов L или UL или LL для long, unsigned long и long long вместо (и строчные версии этих, но суффикс лучше написано в верхнем регистре, чтобы избежать путаницы l и 1). Выбор зависит от того, что вы действительно пытаетесь сделать.

Обратите внимание, что тип результата << - это тип левого операнда. Результат сдвига только затем преобразуется в тип левой стороны оператора присваивания. LHS присвоения не влияет на то, как рассчитывается значение для RHS.

Как user3528438 отметил в comment, и, как я предположил (возможно, ошибочно), вы бы знали - если multiplier (правая часть оператора <<) оценивает отрицательное значение или значение, равное или больше, чем число бит в целочисленном типе, тогда вы вызываете неопределенное поведение.

Отметьте, что long long и unsigned long long являются стандартными в старом стандарте десятилетия и с половиной лет (C99) и более новым стандартом C11, но они не были частью стандарта C89/C90 четверти века. Если вы застряли на платформе, где компилятор находится в дате окончания периода времени в 2013 году и в стандартной версии совместимости C 1990 года, тогда вам нужно пойти на альтернативные 64-битные методы, ориентированные на платформу. Цикл в обновленном вопросе охватывает 33 значения, так как вы считаете от 32 до 0. В 32-битном типе не должно быть разных значений для каждой из 33 смен.

(Продвинутые пользователи могут быть заинтересованы в INT35-C Use correct integer precisions и N1899 — Integer precision bits update; они для некоторых людей являются таинственными эзотериками.Я не уверен, что мне когда-нибудь понадобится беспокоиться по поводу поднятой проблемы.)

Обратите внимание на обсуждение ниже printf() форматов. Вы должны убедиться, что вы печатаете значение с правильным форматом. Для long int, который должен быть %ld; для unsigned long long, это будет %llu. Другие типы требуют других форматов. Убедитесь, что вы используете разумные параметры предупреждения компилятора. Если вы используете GCC, вы должны посмотреть на gcc -Wall -Wextra -Werror -std=c11 как довольно эффективный набор опций; Я использую несколько более строгие параметры, чем те, что я компилирую код C.

+0

Также важно отметить, что '1 << 32' является UB для большинства реализаций, где' 1' является 'int', а' int' меньше или равно 32bits. – user3528438

+0

Хотя это казалось очень разумным решением, к сожалению, это было бесполезно для меня :( – Maxitj

+0

@Maxitj: Не повезло. Я полагаю, это означает, что вы застряли с компиляторами Microsoft. Это стоит сказать так, потому что люди предполагают, что вы используете более или менее современный компилятор, поддерживающий более или менее современный стандарт, если вы не указали иначе. –

0

В зависимости от того, какой компилятор вы используете, и если вы компилируете в 32-битном против 64-битном режиме, что вы видите, может быть точно так, как ожидалось.

https://software.intel.com/en-us/articles/size-of-long-integer-type-on-different-architecture-and-os

Т.Л., д-р: с MSVC, как int и long 32 бита, вы должны закончить до __int64, если вы хотите хранить большее количество. С gcc или другими компиляторами в 32-битном режиме вы сталкиваетесь с той же проблемой int = long = 32-бит, что не поможет вам в вашей ситуации. Только когда вы переходите на 64-битную компиляцию на компиляторах, отличных от Microsoft, делают int и long начинают расходиться.

Редактировать в комментариях: int64_t или long long также будут соответствовать стандартам, которые могут быть использованы. Альтернативно, unsigned позволит плакату соответствовать их значению в 32 бита.

+1

Почему не 'длинный длинный'? – user3528438

+0

длинный тоже тоже. – TezlaCoil

+1

Обратите внимание, что '__int64' специфичен для компиляторов Microsoft (и компиляторов, обеспечивающих совместимость с MS-кодом). Он не стандартизирован каким-либо другим способом. –

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