Я хочу сохранить unsigned char в char с помощью сдвига. Поскольку два типа данных имеют одинаковую длину (1 байт на моей машине), я ожидал, что будет работать следующий код:

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int main () {

        printf ("%d\n", sizeof(char));
        printf ("%d\n", sizeof(unsigned char));

        unsigned char test = 49;
        char testchar = (char) (test - 127);
        printf ("%x\n", testchar);

        return 0;
}

Но это не так. В частности, я получил такой вывод:

1
1
ffffffb2

Это говорит о том, что символ был приведен к int. Есть ли у кого-нибудь объяснение и, надеюсь, решение?

5
gosbi 5 Май 2014 в 13:53

5 ответов

Лучший ответ

%x - спецификатор для 4-байтового int. Для печати одного байта char используйте %hhx.

printf приводит тип своих аргументов в соответствии с переданными ему спецификаторами формата. Вот почему тип testchar был повышен до int.

5
Don't You Worry Child 5 Май 2014 в 10:05

Printf - это функция с переменным аргументом, и поэтому на ее аргументы распространяются правила продвижения по умолчанию. В этом случае ваш char повышается до int, и в этом процессе расширяется знак. Дополнительное двоичное int из 4 байтов с двоичным шаблоном 0xffffffb2 равно -78. Распечатайте его как символ со спецификатором %hhx.

См. Также Какие интегральные рекламные акции имеют место при печати char ?

5
Community 23 Май 2017 в 10:29

Что происходит !!!!

1) unsigned char test = 49; // присваивается шестнадцатеричное значение 31

2) char testchar = (char) (test - 127); // 49-127 = -78 т.е.; 0xb2 (как unsigned), преобразовывая его в signed char результаты F отступ перед b2, чтобы указать его как отрицательный

3) printf ("%x\n", testchar); // Поскольку %x является спецификатором для 4-байтового int (как сказал @ Don't You Worry Child ) ffffffb2, 4 байта выход получен

Так что попробуйте, как сказал @ Don't You Worry Child

2
abhishek_naik 13 Июн 2016 в 03:58

%x предназначен только для печати unsigned int, однако вы предоставляете char.

Использование %x с отрицательным значением char вызывает неопределенное поведение.

В сторону: Спецификация стандарта C для printf не особенно ясна; некоторые считают, что передача чего-либо, кроме точно unsigned int, вызывает неопределенное поведение. Другие (включая меня) считают, что можно передавать аргументы, которые не являются конкретно unsigned int, но после промо-аргументов по умолчанию имеют тип int с неотрицательным значением. Стандарт действительно гарантирует, что неотрицательные int имеют то же представление, что и unsigned int с тем же значением.


В некоторых других ответах предлагается %hhx, но это не лучше, чем %x. Стандарт (при разумной интерпретации) указывает, что %hhx должен использоваться только с аргументом unsigned char, а %hhd должен использоваться только с аргументом signed char. Фактически нет модификатора для простого char.

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

printf ("%hhx\n", (unsigned char)testchar);

Был бы один вариант. Здесь можно использовать IMO %x, но, как упоминалось выше, некоторые с этим не согласны.


NB. Неправильный описатель формата используется в printf ("%d\n", sizeof(char)); и следующей за ним строке. Спецификатор для size_t - %zu. Таким образом, вы можете либо использовать %zu, либо привести аргумент к int, или даже лучше:

printf("1\n");
1
M.M 13 Июн 2016 в 03:35

Я ожидал, что следующий код сработает:

Не будет.

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

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

Таким образом, нет никакой гарантии, что (char) (test - 127) произведет значение, которое может быть представлено char.

C ++ (14) действительно допускает преобразование без потерь между unsigned char и char. Стандарт говорит (3.9.1 / 1):

Для каждого значения i типа unsigned char в диапазоне от 0 до 255 включительно существует значение j типа char такое, что результат интегрального преобразования (4.7) из i в char равно j, а результатом целочисленного преобразования j в unsigned char является i.

0
Nicol Bolas 13 Июн 2016 в 05:28