Печать фактического отрицательного числа, хранящегося внутри unsigned int - PullRequest
0 голосов
/ 13 февраля 2019

У меня странная проблема.У меня есть переменная, фактическое значение которой является только отрицательным (для этой переменной генерируются только отрицательные целые числа).Но в устаревшем коде мой старый коллега использовал uint16 вместо подписанного int для хранения значений этой переменной.Теперь, если я хочу напечатать фактическое отрицательное значение этой переменной, как я могу это сделать (какой спецификатор формата нам)?Например, если фактическое значение равно -75, когда я печатаю с использованием% d, это дает мне 5-значное положительное значение (я думаю, что это из-за дополнения до двух).Я хочу напечатать его как 75 или -75.

Ответы [ 6 ]

0 голосов
/ 13 февраля 2019

Если u является объектом целого типа без знака, и в нем сохраняется отрицательное число, величина которого находится в пределах диапазона u, сохранение -u для объекта типа u приведет коставьте в нем величину этого отрицательного числа.Это поведение не зависит от того, как представляется u.Например, если u и v являются 16-битными unsigned short, а int - 32-битными, то сохранение -60000 в u оставит в нем 5536 [реализация будет вести себя так, как если быдобавляет 65536 к сохраненному значению, пока оно не окажется в диапазоне unsigned short].Оценка -u даст -5536, а сохранение -5536 в v позволит оставить 60000.

0 голосов
/ 13 февраля 2019

Если 16-разрядное отрицательное целое число было сохранено в uint16_t, называемом x, то исходное значение может быть рассчитано как x-65536.

. Может быть напечатано любое из 1 :

printf("%ld", x-65536L);

printf("%d", (int) (x-65536));

int y = x-65536;
printf("%d", y);

Вычитание 65536 работает, потому что:

  • Согласно C 2018 6.5.16.1 2, значение правого операнда (отрицательное 16-разрядное целое число равнопреобразуется в тип выражения присваивания (который по сути является типом левого операнда).
  • Согласно 6.3.1.3 2, преобразование в целое число без знака выполняется путем сложения или вычитания «на единицу больше максимального значениякоторый может быть представлен в новом типе ». Для uint16_t на единицу больше, чем его максимум составляет 65536.
  • С 16-разрядным отрицательным целым числом добавление 65536 один раз приводит его к диапазону uint16_t.
  • Следовательно, вычитание 65536 восстанавливает исходное значение.

Сноска

1 65536 будет long или int в зависимости от того, равен int 16 бит или более, поэтому эти операторы являютсяПравильно обращаться с типом правильно.Первый использует 65536L, чтобы гарантировать тип long.Остальные преобразуют значение в int.Это безопасно, потому что, хотя тип x-65536 может быть long, его значение вписывается в int - если вы не выполняете в реализации C, которая ограничивает int от -32767 до +32767, и оригиналзначение может быть -32768, в этом случае вам следует придерживаться первого варианта.

0 голосов
/ 13 февраля 2019
#include <inttypes.h>

uint16_t foo = -75;
printf("==> %" PRId16 " <==\n", foo); // type mismatch, undefined behavior
0 голосов
/ 13 февраля 2019

Продолжайте с союзом, как объясняется другим ответом.Просто хотел сказать, что если вы используете GCC, есть очень крутая функция, которая позволяет вам выполнять подобный «побитовый» кастинг без написания большого количества кода:

printf("%d", ((union {uint16_t in; int16_t out}) foo).out);

См. https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Cast-to-Union.html.

0 голосов
/ 13 февраля 2019

Предполагая, что ваш друг каким-то образом правильно поместил битовое представление для целого числа со знаком в целое число без знака, единственным стандартным совместимым способом его извлечения было бы использование объединения как -

typedef union {
    uint16_t input;
    int16_t output;
} aliaser;

Теперь,в своем коде вы можете сделать -

aliaser x;
x.input = foo;
printf("%d", x.output);
0 голосов
/ 13 февраля 2019

Если int составляет 32 бита в вашей системе, то правильный формат для печати 16-разрядного целого числа: %hu для без знака и %hd для со знаком.

Проверьте вывод:

uint16_t n = (uint16_t)-75;

printf("%d\n", (int)n); // Output: 65461
printf("%hu\n", n); // Output: 65461
printf("%hd\n", n); // Output: -75
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...