c - 如何 printf ("%0x") 并根据类型确定位数?

标签 c hex printf

我可以指定位数,例如 printf("%08x", ...)。但我想根据数据类型自动调整位数(例如,long(64 位)应自动具有 64/4=16 位数字)。有办法这样做吗?谢谢。

最佳答案

How to printf(“%0x”) with the number of digits determined from the type?

1) 求位宽

使用 sizeof, CHAR_BIT 查找宽度 sizeof(x)*CHAR_BIT1 或参见下文替代方案。

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))

使用允许比无符号字段更宽的语言扩展 - 也能很好地工作。

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

Macro-magic 可以通过编译时间计算来替换 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 当类型中没有填充时,此方法效果很好 - 标准无符号整数类型中常见。

关于c - 如何 printf ("%0x") 并根据类型确定位数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54831198/

相关文章:

c - 链表创建时出现段错误

ruby - 在 Ruby 中将整数转换为十六进制字符串

c - 在c中用双变量打印字符

c++ - 拔河: Divide set of n objects int to subsets

java - 为什么 C 和 Java 的表达式 m++ + (++m) 的输出不同

string - Go中如何将十六进制字符串直接转为[]byte?

bash printf + 回显字符串

c - 带有左对齐标志的 printf() 位置参数

c - 在c中添加到字符串末尾的额外字符

c# - 使用 Newtonsoft JSON 反序列化十六进制值