присвоение 128 переменной char в c - PullRequest
0 голосов
/ 26 июня 2018

На выходе получается 32-разрядное 2-е дополнение к 128, то есть 4294967168. Как?

#include <stdio.h>
int main()
{
    char a;
    a=128;
    if(a==-128)
    {
        printf("%u\n",a);
    }
    return 0;
}

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

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

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

Введите char на вашем компьютере, вероятно, 8-разрядное количество со знаком. Таким образом, его диапазон составляет от -128 до +127. Так что +128 не подходит.

Когда вы пытаетесь вставить значение +128 в 8-разрядное число со знаком, вы, вероятно, получите вместо этого значение -128. И это похоже на то, что происходит с вами, основываясь на том факте, что ваше заявление if, очевидно, успешно выполняется.

Итак, мы попытаемся взять значение -128 и напечатать его, как если бы это был unsigned int, который на вашем компьютере, очевидно, является 32-битным типом. Он может содержать числа в диапазоне от 0 до 4294967295, что, очевидно, не включает -128. Но целые числа без знака, как правило, ведут себя довольно хорошо по модулю их диапазона, поэтому, если мы добавим 4294967296 к -128, мы получим 4294967168, который является именно тем числом, которое вы видели.

Теперь, когда мы поработали над этим, давайте в будущем решим не защемлять числа, которые не вписываются в переменные char, или печатать подписанные величины с помощью спецификатора формата %u.

0 голосов
/ 26 июня 2018

Последовательность шагов, которую вы получили, выглядит примерно так:

  1. Вы назначаете 128 для char.
  2. В вашей реализации char равно signed char и имеет максимальное значение 127, поэтому 128 переполняется.
  3. Ваша реализация интерпретирует 128 как 0x80. Здесь используется математика, дополняющая два, поэтому (int8_t)0x80 представляет (int8_t)-128.
  4. По историческим причинам (относящимся к наборам команд миникомпьютеров DEC PDP, на которых C изначально разрабатывался), C поддерживает подписанные типы короче от int до int во многих контекстах, включая переменные аргументы таких функций, как printf(), которые не связаны с прототипом и по-прежнему используют вместо этого старые правила продвижения аргументов K & R C.
  5. В вашей реализации int имеет ширину 32 бита и также два дополнения, поэтому (int)-128 знак расширяется до 0xFFFFFF80.
  6. Когда вы делаете вызов наподобие printf("%u", x), среда выполнения интерпретирует аргумент int как unsigned int.
  7. Как 32-разрядное целое число без знака, 0xFFFFFF80 представляет 4 294 967 168.
  8. Спецификатор формата "%u\n" выводит это без запятых (или других разделителей), за которыми следует символ новой строки.

Это все законно, но есть и много других возможных результатов. Код глючный и не переносимый.

Убедитесь, что вы не переполняете диапазон вашего типа! (Или, если это неизбежно, переполнение для беззнаковых скаляров определяется как модульная арифметика, так что лучше вести себя.) Обходной путь здесь заключается в использовании unsigned char, который имеет диапазон от 0 до (по крайней мере) 255 вместо char.

0 голосов
/ 26 июня 2018

Компиляция вашего кода с включенными предупреждениями дает:

warning: overflow in conversion from 'int' to 'char' changes value from '128' to '-128' [-Woverflow]

, который говорит вам, что назначение a=128; не определено в вашей платформе.

Стандарт говорят:

6.3.1.3 Целые числа со знаком и без знака

1 Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.

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

3 В противном случае новый тип подписывается и значение не может быть представлено в нем; либо результат определяется реализацией, либо определяется сигнал реализации .

Поэтому мы не можем знать, что происходит, поскольку это зависит от вашей системы.

Однако, если мы сделаем некоторое предположение (и отметим , это всего лишь предположение ):

128 как 8 бит будет 0b1000.0000

поэтому, когда вы звоните printf, где вы получите преобразование в int, будет расширение знака, например:

 0b1000.0000 ==> 0b1111.1111.1111.1111.1111.1111.1000.0000

который - напечатанный как без знака, представляет номер 4294967168

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...