Простая интерпретация символов в C - PullRequest
3 голосов
/ 03 февраля 2012

Вот мой код

 #include<stdio.h>

 void main()
 {
     char ch = 129;
     printf("%d", ch);
 }

Я получаю вывод как -127.Что это значит?

Ответы [ 9 ]

4 голосов
/ 03 февраля 2012

Это означает, что char - это 8-битная переменная, которая может содержать только 2 ^ 8 = 256 значений, поскольку объявление является char ch, ch - это переменная signed, что означает, что она может хранить 127 отрицательные и положительные значения. когда вы просите превысить 127, тогда значение начинается с -128.

Думайте об этом как о некоторых аркадных играх, в которых вы переходите с одной стороны экрана на другую:

ch = 50;

                                    ----->                        50 is stored
      |___________________________________|___________|           since it fits
    -128                       0         50          127          between -127
                                                                  and 128

ch = 129;

                                                    ---           129 goes over
      -->                                                         127 by 2, so
      |__|____________________________________________|           it 'lands' in
    -128  -127                 0                     127          -127

НО !! Вы не должны полагаться на это, поскольку это неопределенное поведение!


В честь Лучиана Григоре вот краткое представление о том, что происходит:

A char - это переменная, которая будет содержать 8 бит или байт. Таким образом, у нас есть 8 0 и 1 изо всех сил, чтобы представить любую ценность, которую вы хотите. Если char является переменной signed, она будет представлять собой положительное или отрицательное число. Вы, вероятно, читали об одном бите, представляющем знак, который является абстракцией истинного процесса; на самом деле это только одно из первых решений, реализованных в электронике. Но у такого тривиального метода была проблема, у вас было бы 2 способа представления 0 (+0 и -0):

0 0000000     ->    +0        1 0000000     ->    -0                    
^                             ^ 
|_ sign bit 0: positive       |_ sign bit 1: negative

Несоответствия гарантированы! Итак, некоторые очень умные люди придумали систему, называемую «Дополнение единичного», которая представляла бы отрицательное число как отрицание (НЕ операция) своего положительного аналога:

01010101      ->    +85
10101010      ->    -85

Эта система ... имела ту же проблему. 0 может быть представлено как 00000000 (+0) и 11111111 (-0). Затем пришли некоторые умные люди, которые создали дополнение к двум, которое будет содержать отрицательную часть более раннего метода, а затем добавит 1, таким образом удаляя этот надоедливый -0 и давая нам новый блестящий номер в нашем диапазоне: -128 !. Так как же теперь выглядит наш ассортимент?

00000000     +0
00000001     +1
00000010     +2
...
01111110     +126
01111111     +127
10000000     -128
10000001     -127
10000010     -126
...
11111110     -2
11111111     -1

Итак, это должно дать представление о том, что происходит, когда наш маленький процессор пытается добавить числа к нашей переменной:

 0110010     50                   01111111     127
+0000010    + 2                  +00000010    +  2
 -------     --                   --------     ---
 0110100     52                   10000001    -127
     ^                                  ^       ^
     |_ 1 + 1 = 10          129 in bin _|       |_ wait, what?!

Да, если вы просмотрите таблицу диапазонов выше, вы можете увидеть, что до 127 (01111111) двоичный файл был в порядке и великолепен, ничего странного не происходило, но после того, как 8-й бит установлен в -128 (* 1043) *) интерпретируемое число больше не относится к его двоичной величине, а к представлению дополнения двух. Это означает, что двоичное представление, биты в вашей переменной, 1 и 0, сердце нашего любимого char, содержит 129 ... его там, посмотрите на это! Но злой процессор читает, что, как ничтожно-127, переменная HAD будет signed, подрывая весь ее положительный потенциал для вонючего сдвига через линию действительных чисел в евклидовом пространстве размерности один.

2 голосов
/ 03 февраля 2012

Это означает, что вы столкнулись с неопределенным поведением .

Возможен любой исход.

char ch=129; - это UB, поскольку 129 не является представимым значением для char для вашей конкретной настройки.

1 голос
/ 03 февраля 2012

Это происходит из-за того, что char кодируется в одном байте, поэтому 8 бит данных.

Фактически char имеет значение, закодированное в 7 битах и ​​имеет один бит для знака, unsigned char имеет 8 бит данных для своего значения.

Это означает:

Принимая abcdefgh как 8 битов соответственно (самый левый бит, а h самый правый), значение кодируется с помощью знака a и bcdefgh в двоичном формате для реального значения:

42 (десятичный) = 101010 (двоичный) хранится как: ABCDEFGH 00101010

При использовании этого значения из памяти: a равно 0: число положительное, bcdefgh = 0101010: значение равно 42

Что происходит, когда вы ставите 129:

129 (десятичный) = 10000001 (двоичный) хранится как: ABCDEFGH 10000001

При использовании этого значения из памяти: a равно 0: число отрицательное, мы должны вычесть один и инвертировать все биты в значении, поэтому (bcdefgh - 1) inverted = 1111111: значение 127 Номер -127

1 голос
/ 03 февраля 2012

Ваш char, скорее всего, представляет собой 8-разрядное целое число со знаком, которое хранится с использованием дополнения до двух . Такая переменная может представлять только числа от -128 до 127. Если вы сделаете "127 + 1", она будет округлена до -128. Таким образом, 129 эквивалентно -127.

1 голос
/ 03 февраля 2012

В вашей системе: char 129 имеет те же биты, что и 8-битовое целое число со знаком -127.Целое число без знака изменяется от 0 до 255, а целое число без знака от -128 до 127.

Related (C ++):

Вам также может быть интересно прочитать хороший верхний ответ на вопрос Чтотакое неподписанный символ?

Как указывает @jmquigley.Это строго неопределенное поведение, и вы не должны на него полагаться. Разрешение целочисленных переполнений со знаком в C / C ++

0 голосов
/ 03 февраля 2012

Является ли простой char подписанным или неподписанным, определяет поведение реализации . Это довольно глупое, неясное правило на языке Си. int, long и т. Д. Гарантированно будут подписаны, но char может быть подписано или без знака, это зависит от реализации компилятора.

На вашем конкретном компиляторе char явно подписано. Это означает, что если ваша система использует дополнение до двух, она может содержать значения от -128 до 127.

Вы пытаетесь сохранить значение 129 в такой переменной. Это приводит к неопределенному поведению , потому что вы получаете целочисленное переполнение. Строго говоря, когда вы это делаете, может произойти все что угодно. Программа может напечатать «hello world» или начать снимать невинных прохожих и при этом соответствовать стандарту ISO C. Однако на практике большинство (все?) Компиляторов будут реализовывать это неопределенное поведение как «обтекание», как описано в других ответах.

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

Код можно переписать, например:

unsigned char ch = 129;

Или даже лучше:

#include <stdint.h>
...
uint8_t ch = 129;

Как правило, следуйте этим правилам в MISRA-C: 2004:

6.1 Простой тип char должен использоваться только для хранения и использования символьных значений.

6,2 со знаком и беззнаковый тип должен использоваться только для хранения и использования числовых значений.

0 голосов
/ 03 февраля 2012

char - 8 бит, подписано . Он может содержать только значения от -128 до 127. Когда вы попытаетесь присвоить ему 129, вы получите результат, который видите, потому что бит, который указывает на подписание, перевернулся. Другой способ думать об этом состоит в том, что число «оборачивается» вокруг.

0 голосов
/ 03 февраля 2012

Тип char может быть либо signed, либо unsigned, это зависит от компилятора.Большинство компиляторов имеют его как «подписанный».

В вашем случае компилятор молча преобразует целое число 129 в подписанный вариант и помещает его в 8-битное поле, что дает -127.

0 голосов
/ 03 февраля 2012

Тип char представляет собой 8-разрядное целое число со знаком.Если вы интерпретируете представление беззнакового байта 129 в дополнении до двух *1003* подписанного представления, вы получите -127.

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