Странный вопрос относительно целочисленного типа C и спецификатора printf()

#c #integer

#c #целое

Вопрос:

Хорошо, я знаю, что этот вопрос может показаться странным, но все же я хотел развенчать его.

1.) int тип в C может хранить число в диапазоне от -2147483648 до 2147483647.

2.) Если мы добавим перед ним unsigned it , диапазон станет от 0 до 2147483647.

3.) Дело в том, зачем нам вообще использовать ключевое слово unsigned , когда приведенный ниже код действительно мог бы работать.

Код:

 #include <stdio.h>

int main(void)
{
    int num = 2147483650;

    printf("%un" , num);

    return 0;
}
  

4.) Как вы видите, я все еще могу распечатать целое число как тип без знака, если я использую %u спецификатор, и он выведет мне значение 2147483650 .

5.) Даже если я создам другой целочисленный тип со значением 50 и суммирую его со num , хотя это переполнение, но все же я все равно могу распечатать правильное значение суммы с помощью %u спецификатора.Итак, почему unsigned ключевое слово все еще необходимо??

Спасибо, что потратили время на чтение моего вопроса.

Комментарии:

1. Помимо неопределенного поведения, печать — далеко не единственная значимая операция над ( unsigned ) целыми числами.

Ответ №1:

  1. Нет, это верно только на определенных платформах (где int является 32-разрядным, с дополнением 2).

  2. Нет, в этом случае диапазон был бы от 0 до 4294967295.

  3. Этот код демонстрирует неопределенное поведение.

  4. Смотрите 3.

  5. Смотрите 2. и 3.

Ответ №2:

Рассматривая только Q3, «Почему мы утруждаем себя использованием unsigned», рассмотрим этот фрагмент программы:

 int main(void) {

  int num = MAX_INT;
  num  = 50;

  printf("%un", num); /* Yes, this *might* print what you want */

  /* But this "if" almost certainly won't do what you want. */
  if(num > 0) {
    printf("Big numbers are bign");
  } else {
    printf("Big numbers are smalln");
  }
} 
  

Мы используем «без знака», потому что unsigned int поведение отличается от int . Есть более интересные варианты поведения, чем просто то, как printf работает.

Комментарии:

1. Для целых чисел без знака чаще всего используются биты. Целые числа со знаком ведут себя иначе при сдвиге или повороте на несколько бит, чем целые числа без знака.

Ответ №3:

Ну, во-первых, результат присвоения номера вне диапазона определяется реализацией — ему не обязательно давать значение, которое будет «работать» при печати с помощью %u спецификатора формата. Но чтобы действительно ответить на ваш вопрос, рассмотрите эту модификацию вашего кода:

 #include <stdio.h>

int main(void)
{
    int num = 2147483650;
    unsigned num2 = 2147483650;

    num /= 2;
    num2 /= 2;

    printf("%u, %un" , num, num2);

    return 0;
}
  

(Если 2147483650 находится вне диапазона int на вашей платформе, но в пределах диапазона unsigned , тогда вы получите правильный ответ только 1073741825, используя unsigned тип).

Ответ №4:

  1. Неверно. Диапазон от INT_MIN (который в двух системах комплектации обычно равен -INT_MAX 1) до INT_MAX; INT_MAX и INT_MIN зависят от компилятора, архитектуры и т.д.

  2. Неверно. Диапазон от 0 до UINT_MAX, который обычно равен INT_MAX * 2 1

  3. Целые числа без знака имеют другое поведение в отношении переполнения и семантики. В дополнении 2 есть одно значение, неопределенное для целых чисел со знаком (то есть, если установлен только самый верхний бит, остальные равны нулю), что имеет несколько двойное значение. Целые числа без знака могут использовать весь диапазон битовых шаблонов.

  4. Вот упражнение: на 32-разрядной машине сравните выходные данные printf(«%d % u», 0xffffffff, 0xffffffffff);

  5. Потому что целые числа без знака ведут себя иначе, чем целые со знаком.

Комментарии:

1. @Oli: Ты прав, еще раз.

2. Все еще неверно: игнорирование переполнений является -INT_MAX - 1 или -(INT_MAX 1)