Печать шестнадцатеричных символов в C
Я пытаюсь прочитать строку символов, а затем распечатать шестнадцатеричный эквивалент символов.
Например, если у меня есть строка "0xc0 0xc0 abc123"
, где первые 2 символа c0
в шестнадцатеричном формате, а остальные символы abc123
в ASCII, то я должен получить
c0 c0 61 62 63 31 32 33
Однако printf
с помощью %x
дает мне
ffffffc0 ffffffc0 61 62 63 31 32 33
Как получить результат, который я хочу, без "ffffff"
? И почему только c0 (и 80) имеет ffffff
, но не другие символы?
Ответы
Ответ 1
Вы видите ffffff
, потому что char
подписан в вашей системе. В C функции vararg, такие как printf
, будут продвигать все целые числа, меньшие, чем int
, на int
. Поскольку char
является целым числом (8-разрядное целое число со знаком в вашем случае), ваши символы повышаются до int
через расширение знака.
Так как c0
и 80
имеют ведущие 1-битные (и являются отрицательными как 8-битовое целое), они расширяются по значению, а другие в вашем примере этого не делают.
char int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
Здесь решение:
char ch = 0xC0;
printf("%x", ch & 0xff);
Это замаскирует верхние биты и сохранит только более низкие 8 бит.
Ответ 2
В самом деле, есть преобразование типа в int.
Также вы можете заставить тип char с помощью спецификатора% hhx.
printf("%hhX", a);
Ответ 3
Вы можете создать неподписанный char:
unsigned char c = 0xc5;
Печать будет давать C5
, а не ffffffc5
.
Только символы размером больше 127 печатаются с помощью ffffff
, потому что они отрицательны (char подписан).
Или вы можете нарисовать char
во время печати:
char c = 0xc5;
printf("%x", (unsigned char)c);
Ответ 4
Вероятно, вы сохраняете значение 0xc0 в переменной char
, что, вероятно, является подписанным типом, а ваше значение отрицательное (самый старший бит установлен). Затем при печати он преобразуется в int
, а для сохранения семантической эквивалентности компилятор добавляет дополнительные байты с 0xff, поэтому отрицательный int
будет иметь такое же числовое значение вашего отрицательного char
. Чтобы исправить это, просто нажмите unsigned char
при печати:
printf("%x", (unsigned char)variable);
Ответ 5
Вы можете использовать hh
, чтобы сообщить printf
, что аргумент является unsigned char. Используйте 0
, чтобы получить нулевое дополнение и 2
, чтобы установить ширину в 2. x
или x
для шестнадцатеричных символов с более низким/верхним регистром.
uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"
Изменить. Если читатели обеспокоены утверждением 2501, что это как-то не "правильные" спецификаторы формата, я предлагаю прочитать printf
ссылка. В частности:
Несмотря на то, что% c ожидает аргумент int, безопасно передавать char из-за целочисленного продвижения, которое происходит, когда вызывается вариационная функция.
Правильные спецификации преобразования для типов символов фиксированной ширины (int8_t и т.д.) определены в заголовке <cinttypes>
(С++) или <inttypes.h>
(C) (хотя PRIdMAX, PRIuMAX и т.д. являются синонимами % jd,% ju и т.д.).
Что касается его утверждения о подписанном vs без знака, в этом случае это не имеет значения, поскольку значения всегда должны быть положительными и легко вписываться в подписанный int. В любом случае не существует спецификатора формата hexideximal.
Изменить 2: ( "когда-то-признать-вы ошибаетесь" ):
Если вы прочитали фактический стандарт C11 на странице 311 (329 из PDF), вы найдете:
hh: указывает, что для аргумента signed char
или unsigned char
применяется следующий d
, i
, o
, u
, o
, u
, x
или x
были повышены в соответствии с целыми рекламными акциями, но перед печатью его значение должно быть преобразовано в signed char
или unsigned char
); или что следующий указатель преобразования n
применяется к указателю на аргумент signed char
.
Ответ 6
Вероятно, вы печатаете из подписанного массива char. Либо печатайте из массива без знака char, либо замаскируйте значение с помощью 0xff: например. ar [i] и 0xFF. Значения c0 расширяются, потому что установлен бит (знаковый).
Ответ 7
Попробуйте что-то вроде этого:
int main()
{
printf("%x %x %x %x %x %x %x %x\n",
0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}
Что производит это:
$ ./foo
c0 c0 61 62 63 31 32 33