Как распечатать f ("% 0x") с количеством цифр, определенных из типа? - PullRequest
0 голосов
/ 22 февраля 2019

Я могу указать количество цифр, как printf("%08x", ...).Но я хотел бы автоматически настроить количество цифр в соответствии с типом данных (например, long (64 бита) должно автоматически иметь 64/4 = 16 цифр).Есть ли способ сделать это?Спасибо.

Ответы [ 2 ]

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

Вы, вероятно, должны смотреть в C

#include <inttypes.h>

unit8_t value = 0x34;
printf("The value formatted for 8 bits is %" PRIx8 ".", value);

Обратите внимание, что PRIx8 - это строка, которая правильно отформатирует для "printf" "шестнадцатеричный" "восемь битов".

Обратите внимание, что отсутствие запятых между строками не является ошибкой.Это метод форматирования, который использует функцию C, называемую «автоматическая конкатенация строк», так что три строки будут соединены вместе.PRIx8 - это просто удобство, которое означает правильное форматирование для 8-битного шестнадцатеричного значения.

Чтобы получить аналогичный форматированный формат для 32-битного кода, вы должны использовать PRIx32.

Длякраткий обзор форматов вывода inttypes.h, вы можете посмотреть на Хорошее введение в

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

Как printf(“%0x”) с количеством цифр, определенным из типа?

1) Найти ширину бита

Использовать sizeof, CHAR_BIT, чтобы найти бит ширина sizeof(x)*CHAR_BIT 1 или см. Ниже альтернативу.

2) Найти ширину куска

(bit_width + 3)/4 для клев ширина - количество шестнадцатеричных символов.

3) Передать ширину

Используйте "*" для передачиuintmax_t.

#include <float.h>
#include <limits.h>
#include <stdio.h>

#define PRINTF_XW(x) printf("%0*jx\n", (int)(sizeof(x)*CHAR_BIT+3)/4, (uintmax_t) (x))

int main(void) {
  unsigned char uc = 1;
  unsigned short us = 2;
  unsigned u = 3;
  unsigned long ul = 4;
  unsigned long long ull = 5;
  uintmax_t uj = 6;

  PRINTF_XW(uc);
  PRINTF_XW(us);
  PRINTF_XW(u);
  PRINTF_XW(ul);
  PRINTF_XW(ull);
  PRINTF_XW(uj);
  return 0;
}

. Пример вывода, может отличаться для разных платформ.

01
0002
00000003
0000000000000004
0000000000000005
0000000000000006

Альтернатива

Другой подход будет использовать _Generic - это немного больше работы - и больше наград.
См. unsigned long long uf:42; пример ниже.

#include <float.h>
#include <limits.h>
#include <stdint.h>

int hexwidth(uintmax_t u) {
  int count = 3;
  while (u) {
    u >>= 1;
    count++;
  }
  return count/4;
}

// Default case useful for other unsigned types wider than `unsigned`
#define HEXWIDTH(s) _Generic((s), \
    unsigned char: hexwidth(UCHAR_MAX), \
    unsigned short: hexwidth(USHRT_MAX), \
    unsigned : hexwidth(UINT_MAX), \
    unsigned long: hexwidth(ULONG_MAX), \
    unsigned long long: hexwidth(ULLONG_MAX), \
    default: hexwidth((s)*0u - 1u) \
    )

#define PRINTF_XW(x) printf("%0*jx\n", HEXWIDTH(x), (uintmax_t) (x))

Сязыковые расширения, которые допускают более широкие поля, чем unsigned - тоже хорошо работают.

int main(void) {
  struct {
      unsigned long long uf:42;
  } s1 = {7};
  struct {
      unsigned long long uf:51;
  } s2 = {8};

  PRINTF_XW(s1.uf);
  PRINTF_XW(s2.uf);
}

Вывод

00000000007   <-- 11 digits
0000000000008 <-- 13 digits

Макромагия может заменить hexwidth(uintmax_t u) следующим образом с вычислением времени компиляции:

#define NW3(x) (((x) > 0xFu) ? 2 : 1)
#define NW4(x) (((x) > 0xFFu) ? NW3((x)>>8)+2 : NW3(x))
#define NW5(x) (((x) > 0xFFFFu) ? NW4((x)>>16)+4 : NW4(x))
#define NW6(x) (((x) > 0xFFFFFFFFu) ? NW5((x)>>32)+8 : NW5(x))
#define NW(x) (((x) > 0xFFFFFFFFFFFFFFFFu) ? NW6((((x)+0llu)>>32)>>32)+16 : NW6((x)+0llu))

// Default case useful for all unsigned types as wide/wider than `unsigned`
#define HEXWIDTH(s) _Generic((s), \
    unsigned char: NW(UCHAR_MAX), \
    unsigned short: NW(USHRT_MAX), \
    default: NW((s)*0u - 1u) \
    )

1 Это хорошо работает, когда в типе нет заполнения - обычно среди стандартных беззнаковых целочисленных типов.

...