Вывести правильный формат от двойного значения до шестнадцатеричного - PullRequest
0 голосов
/ 08 ноября 2018
    #include <stdio.h>

    typedef unsigned char*pointer;

    void show_bytes(pointer start, size_t len)
    {
         size_t i;
         for (i = 0; i < len; i++)
             printf("%p\t0x%04x\n",start+i, start[i]);
         printf("\n");
    }

    int main()
    {
        double a = 4.75;
        printf("Double demo by %s on %s %s\n", "Toan Tran", __DATE__,     __TIME__);
        printf("Double a = %.2f (0x%08x)\n", a, a);
        show_bytes((pointer) &a, sizeof(double));
    }

Вывод:

Double demo by Toan Tran on Nov  8 2018 11:07:07
Double a = 4.75 (0x00000100)
0x7ffeee7a0b38  0x0000
0x7ffeee7a0b39  0x0000
0x7ffeee7a0b3a  0x0000
0x7ffeee7a0b3b  0x0000
0x7ffeee7a0b3c  0x0000
0x7ffeee7a0b3d  0x0000
0x7ffeee7a0b3e  0x0013
0x7ffeee7a0b3f  0x0040

Для этой строки:

printf("Double a = %.2f (0x%08x)\n", a, a);

Я хочу напечатать результат start[i] Возвращаемое шестнадцатеричное значение не является правильным значениемза двойной.Я хочу, чтобы он вернул 0x40130000000000 ...

Пожалуйста, помогите.

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Чтобы разрешить печать шестнадцатеричного дампа любого объекта, передайте его адрес и длину.

void show_bytes2(void *start, size_t size) {
  int nibble_width_per_byte = (CHAR_BIT + 3) / 4;   // Often 2

  unsigned char *mem = start;
  // Highest bytes first
  for (size_t i = size; i>0; ) {
    printf("%0*x", nibble_width_per_byte, mem[--i]);
  }
  printf("\n");

  // Lowest bytes first
  while (size--) {
    printf("%0*x", nibble_width_per_byte, *mem++);
  }
  printf("\n");
}

Используйте "%a", чтобы напечатать значения * double в шестнадцатеричном формате.

int main() {
  double a = 4.75;
  printf("Double a = %a %e %f %g\n", a, a, a, a);
  show_bytes2(&a, sizeof a);
}

выход

Double a = 0x1.3p+2 4.750000e+00 4.750000 4.75
4013000000000000  // I want it to return 0x40130000000000...
0000000000001340
0 голосов
/ 08 ноября 2018

Спецификатор формата %x ожидает аргумент unsigned int, но вы передаете double. Использование неправильного спецификатора формата вызывает неопределенное поведение .

Чтобы напечатать представление double, вам необходимо напечатать каждый отдельный байт в шестнадцатеричном виде с использованием символьного указателя. Это именно то, что вы делаете в show_bytes, и это правильный способ сделать это.

Кроме того, при печати указателя со спецификатором формата %p вы должны привести указатель к void *, чего и ожидает %p. Это один из редких случаев, когда требуется приведение к void *.

У вас может возникнуть соблазн сделать что-то вроде этого:

printf("%llx", *((unsigned long long *)&a));

Однако это нарушение строгого правила наложения имен. Вам нужно будет использовать memcpy для копирования байтов в другой тип:

static_assert(sizeof(unsigned long long) == sizeof(double));
unsigned long long b;
memcpy(&b, &a, sizeof(a));
printf("%llx", b);

Вы также можете сделать это с помощью объединения:

union dval {
    double d;
    unsigned long long u;
};

union dval v;
v.d = d;
printf("%llx", v.u);
...