Печать отрицательного значения в c через printf - PullRequest
0 голосов
/ 26 июня 2019

Я использую тестовый код для изучения C. Однако мне интересно узнать представление отрицательных чисел в шестнадцатеричном формате, для которого я написал тест-код.К моему удивлению, запустив этот тест-код, я получаю только ноль

    union unin
    {
        char chrArray[4];
        float flotVal;
    }uninObj;

    uninObj.flotVal = -25;

    printf("%x %x %x %x",uninObj.chrArray[0], uninObj.chrArray[1], /
           uninObj.chrArray[2], uninObj.chrArray[3]);
    printf("\n Float in hex: %x",uninObj.flotVal);
    return 0;

Ответы [ 3 ]

4 голосов
/ 26 июня 2019

Передача float в спецификатор, ожидающий, что unsigned int равно неопределенное поведение .

Кроме того, unsigned int, ожидаемый %x, не гарантируется равным размеру float. Так что попытка обмануть printf таким способом может или не может "сработать".

В любом случае, для переменной функции, такой как printf, компилятор будет выдавать аргумент типа от float до double, так что это может быть причиной того, что вы (и я) получаете 0 выходные данные.

В моей системе
sizeof(double) - это 8.
sizeof(unsigned int) равно 4.

И если вы посмотрите на выходные байты для этой части union, первые два будут 0. Таким образом, передав 8 байт функции вместо 4, ожидаемых %x, данные выровнены таким образом, что %x получает четыре 0 байта значения.

1 голос
/ 26 июня 2019

В моей архитектуре CentOS 7 Intel 64 sizeof (float) равен 4. Столь малый порядковый результат, который я вижу в моем тесте 00 00 C8 C1, является отрицательным числом.Представление Intel с плавающей запятой одинарной точности:

1 bit sign
8 bit exponent
23 bit significand (with the first 1 bit implied)

Поскольку архитектура Intel имеет младший порядок, значение с плавающей запятой для 00 00 C8 C1 равно 1100 0001 1100 1000 0000 0000 0000 0000.Первая 1 означает, что число отрицательное.Следующие 8 битов 10000011 (десятичный 131) - это показатель степени, а следующие 4 бита 1001 с подразумеваемым 1 битом 11001 - это число 25, сдвинутое вправо на 4 бита.Показатель 131 смещен от 127 на 4, что является числом битов, которое 1.1001 сдвигается влево, чтобы вернуться к 25.

В 64-разрядном представлении показатель равен 11 битам, исмещение экспоненты равно 1023. Таким образом, можно ожидать, что число будет 1 (отрицательный знак), десятичное 1027 в 11 битах 100 0000 0011, затем 25 десятичных как 1001 с подразумеваемым ведущим 1 битом (как в версии с одинарной точностью),тогда все нули, которые вместе составляют C0 39 00 00 , 00 00 00 00.Вы можете видеть, что последние 4 байта - все нули.Но это все еще little-endian, так что 64-битное число будет выглядеть как 00 00 00 00 00 00 39 C0.Таким образом, вы получаете все нули, если печатаете первые 4 байта.

Вы могли бы видеть ненулевые значения из вашей программы, либо (a) указав в объявлении массив из 8 символов и напечатав все 8 (и выувидели бы два байта с 39 C0) или (b) использование значения, отличного от -25, в вашем тесте, для которого требуется больше двоичных цифр для представления в виде большого простого числа или иррационального числа (как предложено @David C. Rankin).

Проверка sizeof (float) определит, какой у вас размер с плавающей запятой (в байтах), и я ожидаю, что вы увидите его как 8, потому что вы видите нули, а не C8 C1, как я.

0 голосов
/ 27 июня 2019

Прежде всего, это утверждение неверно:

printf("\n Float in hex: %x",uninObj.flotVal);

%x ожидает, что его соответствующий аргумент будет unsigned int, и передан аргумент другого типа (как вы делаете здесь) приводит к неопределенному поведению - вывод может быть буквально любым.

Начиная с C99, вы можете использовать спецификаторы %a или %A для печати шестнадцатеричного представления значения с плавающей запятой ([+|-]<em>x</em>.<em>xxxx</em>..., где каждый x - шестнадцатеричная цифра).Однако это не то же самое, что двоичное представление значения в памяти.

Для объединения я рекомендую использовать unsigned char для chrArray и %hhx для распечатки каждого байта:

union unin
{
    unsigned char chrArray[sizeof (float)];
    float flotVal;
}uninObj;

printf("%hhx %hhx %hhx %hhx",uninObj.chrArray[0], uninObj.chrArray[1], 
       uninObj.chrArray[2], uninObj.chrArray[3]);    

Модификатор длины hh в%hhx говорит, что соответствующий аргумент имеет тип unsigned char, а не unsigned int %x, как обычно ожидает.

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