2016-07-10 3 views
4

Я просто попытался опустить без знака int ниже 0. К моему удивлению, это работает!Почему беззнаковый int ниже нуля возможен?

#include<stdio.h> 

int main(void) 
{ 
     unsigned int foo = 5; 
     foo -= 10; 
     printf("%d", foo); 
     return 0; 
} 

Собран с

clang -Weverything main.c 

Эта программа returnes

-5 

Как this пост и мои личные состояния знаний, это не представляется возможным. Но почему это работает? Я что-то упускаю? Это из-за неопределенного поведения? Или это printf? Или что-то другое?

+0

Ах. Это то, о чем я думал. Как я могу его изменить? Какая реальная ценность и как я могу это проверить? –

+0

Эффект 'printf' уже получил ответ. Теперь, чтобы убедиться, что компилятор действительно не считает, что 'foo' отрицательный, добавьте следующее в конец:' if (foo <0) printf («this not not print»); ' – dxiv

+0

О, хорошо. Моя идея состояла в том, чтобы использовать это как держатель государства для робота, и мне не нужно было бы защищать диапазон ниже нуля. Тогда это невозможно:/ –

ответ

7

Эта программа использует printf для повторного интерпретации значения unsigned int как целое число со знаком. Несмотря на то, что это не является проблемой, когда значение unsigned int также подходит в int, это неопределенное поведение:

Если какой-либо аргумент не правильный тип для соответствующей спецификации преобразования, поведение не определено

Пояснение: Вычитание десяти из пяти «оберток», поэтому вы получаете большое количество, основанное на представлении вашей системы unsigned int. Оказывается, бит-представление этого большого числа соответствует представлению отрицательной пятерки в вашей системе, поэтому, когда printf переинтерпретирует значение как подписанное, печатается отрицательная пятая.

Почему нет комментариев от компилятора?

См. this Q&A для возможного объяснения.

4

printf() интерпретирует значение foo как целое число со знаком. Попробуйте заменить% d на% u.

Редактировать: Как сказал dasblinkenlight, это неопределенное поведение. Спецификация языка программирования не говорит, что нужно делать, если это происходит, поэтому оно остается до реализации. Иногда это может привести к другому результату, но в этом случае, вероятно, этого не произойдет.

+0

Спасибо, почему нет никакого уведомления от компилятора? Что видят другие фокусы? –

+0

Компиляторы не выдают предупреждений для всех неопределенных действий. Я отчетливо помню, как однажды кто-то узнал о значении sizeof (void).Пустота не имела размера, но я продолжал настаивать, что это было 4, потому что я делал printf («% d \ n», sizeof (void)); Кроме того, в другом ответе на этот вопрос есть объяснение того, как именно значение получилось интерпретированным как -5, если вы хотите его прочитать :) – godisgood4

+0

Неопределенное поведение не означает показ другого значения. Результат операции хорошо определен. И 'sizeof (void)' должен генерировать ошибку. Во всяком случае, '% d' для' size_t' также является UB (как может быть '% u'). – Olaf

0

Номера на компьютерах хранятся в форме дополнения к двум. И отрицательное число, представленное в дополнении 2, является допустимым числом в диапазоне без знака. Ядро процессора умело реализует сложение/вычитание/умножение/деление, так что ему не нужно знать знак чисел для выполнения этих операций. Язык C, который использует это ядро, передал эти числа в арифметическую единицу процессора, которые выполняют запрошенную операцию и возвращают результат. Вот почему вы получили результат, как ожидалось, в целых числах.

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