ASCII и printf - PullRequest
       28

ASCII и printf

2 голосов
/ 07 октября 2010

У меня есть небольшой (большой, тупой?) Вопрос о int и символах в C. Я помню из своих исследований, что «символы - это маленькие целые числа и наоборот», и это нормально. Если мне нужно использовать небольшие числа, лучше всего использовать тип символа.

Но в коде, подобном этому:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
  int i= atoi(argv[1]);
  printf("%d -> %c\n",i,i);
  return 0;
}

Я могу использовать в качестве аргумента любое число, которое хочу. Таким образом, с 0-127 я получаю ожидаемые результаты (стандартная таблица ASCII), но даже с большими или отрицательными числами это работает ...

Вот пример:

-181 -> K
-182 -> J
300 -> ,
301 -> -

Почему? Мне кажется, что он катается за столом ASCII, но я не понимаю, как.

Ответы [ 7 ]

5 голосов
/ 07 октября 2010

Когда вы передаете int, соответствующий спецификатору преобразования "% c", int преобразуется в unsigned char и затем записывается.

Передаваемые вами значения преобразуются в разные значения, когда они находятся за пределами диапазона без знака (от 0 до UCHAR_MAX).Система, над которой вы работаете, вероятно, имеет UCHAR_MAX == 255.

При преобразовании типа int в неподписанный символ:

  • Если значение больше, чем UCHAR_MAX, (UCHAR_MAX + 1)вычитается из значения столько раз, сколько необходимо для его перевода в диапазон от 0 до UCHAR_MAX.
  • Аналогично, если значение меньше нуля, (UCHAR_MAX + 1) добавляется к значению столько раз, скольконеобходимо перевести его в диапазон от 0 до UCHAR_MAX.

Следовательно:

(unsigned char)-181 == (-181 + (255+1)) == 75 == 'K'
(unsigned char)-182 == (-182 + (255+1)) == 74 == 'J'
(unsigned char)300  == (300 - (255+1))  == 44 == ','
(unsigned char)301  == (301 - (255+1))  == 45 == '-'
2 голосов
/ 07 октября 2010

Параметр формата% c интерпретирует соответствующее значение как символ, а не как целое число.Однако, когда вы врете printf и передаете int в том, что говорите, что это char, его внутренняя манипуляция со значением (чтобы вернуть char, так как char обычно передается как int в любом случае с varargs) приводит кзначения, которые вы видите.

1 голос
/ 07 октября 2010

Я предполагаю, что% c берет первый байт предоставленного значения и форматирует его как символ. В системе с прямым порядком байтов, такой как ПК под управлением Windows, этот байт будет представлять наименее значимый байт из всех переданных значений, поэтому последовательные числа всегда будут отображаться в виде разных символов.

0 голосов
/ 07 октября 2010

Когда мы используем% c в выражении printf, он может получить доступ только к первому байту целого числа.Следовательно, все, что больше 256, рассматривается как n% 256.

Например, i / p = 321 дает op = A

0 голосов
/ 07 октября 2010

Вы сказали, что это число является символом, поэтому он будет стараться изо всех сил рассматривать его как единое целое, несмотря на то, что он слишком большой.Глядя на то, что вы получили, поскольку J и K находятся в таком порядке, я бы сказал, что оно использует целое число% 128, чтобы убедиться, что оно соответствует допустимому диапазону.

0 голосов
/ 07 октября 2010

Редактировать: Пожалуйста, не обращайте внимания на этот "ответ".

Потому что вы находитесь на машине с прямым порядком байтов :) Серьезно, это неопределенное поведение. Попробуйте изменить код на printf("%d -> %c, %c\n",i,i,'4'); и посмотрите, что произойдет ...

0 голосов
/ 07 октября 2010

Что делает atoi, так это преобразовывает строку в числовые значения, так что «1234» получает 1234, а не просто последовательность порядковых чисел строки.

Пример:

char *x = "1234";  // x[0] = 49, x[1] = 50, x[2] = 51, x[3] = 52 (see the ASCII table)
int y = atoi(x); // y = 1234
int z = (int)x[0];  // z = 49 which is not what one would want
...