如何使用复合文字来“fprintf()”具有任意基数的多个格式化数字?

Posted

技术标签:

【中文标题】如何使用复合文字来“fprintf()”具有任意基数的多个格式化数字?【英文标题】:How to use compound literals to `fprintf()` multiple formatted numbers with arbitrary bases? 【发布时间】:2016-03-21 09:51:54 【问题描述】:

我想将多个数字转换为某种表示形式,然后使用*printf() 说明符的标志、宽度和精度。首选是避免使用全局或static 缓冲区。关键问题似乎是如何为每个转换后的数字提供char[]

fprintf(ostream, "some_format", foo(int_a, base_x), foo(int_b, base_y), ...);

如何使用 C11 复合字面量来解决这个问题? 如何使用 C99(或更高版本)复合文字来解决这个问题?

【问题讨论】:

为什么只有 C11?它也适用于/可以解决/与 C99 一起使用。 您的意思是要使用%s 而不是%d 或其他什么? @M.M 使用"%s",或"%d" 或其他。我不想扼杀新奇的想法。 @alk Q & A 根据您的正确观察进行了修改。 【参考方案1】:

C99 C11 引入了复合文字,它不仅允许复杂的初始化结构,还允许“内联”变量。

代码可以调用转换函数并在每个函数调用中传入一个新缓冲区(char [UTOA_BASE_N])0,从而允许函数返回相同的缓冲区,现在根据需要编写,仍在其生命周期内。然后使用"%s" 说明符可用的各种标志、宽度和精度打印返回的字符串。

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

// Maximum buffer size needed
#define UTOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 1)

char *utoa_base(char *s, unsigned x, unsigned base) 
  s += UTOA_BASE_N - 1;
  *s = '\0';
  if (base >= 2 && base <= 36) 
    do 
      *(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x % base];
      x /= base;
     while (x);
  
  return s;


#define TO_BASE(x,b) utoa_base((char [UTOA_BASE_N])0 , (x), (b))

void test(unsigned x) 
  printf("base10:%10u base2:%5s  base36:%s ", x, TO_BASE(x, 2), TO_BASE(x, 36));
  printf("%lu\n", strtoul(TO_BASE(x, 36), NULL, 36));


int main(void) 
  test(0);
  test(25);
  test(UINT_MAX);

输出

base10:         0 base2:    0  base36:0 0
base10:        25 base2:11001  base36:P 25
base10:4294967295 base2:11111111111111111111111111111111  base36:1Z141Z3 4294967295

参考:Is there a printf converter to print in binary format? 有很多答案,但没有一个允许上述简单的内存管理(没有static),可以访问fprintf() 标志宽度、精度和使用完整的数字范围。

这是Answer your own question 的答案。

【讨论】:

注意:我断言返回值仍在范围内,因为“......它的生命周期从进入与其关联的块开始,直到该块的执行以任何方式结束。(输入封闭的块或调用函数会暂停但不会结束当前块的执行。)” C11dr §6.2.4 6 @chux:我认为你是对的,但范围和生命周期是不同的概念。一个对象有一个生命周期;标识符有一个范围。与生命周期不同,作用域可以是不连续的。 是的,是的,是的,这个答案(的例子)说明了为什么我们应该喜欢复合 literals! ;-) @rici 这是故意的。复合文字没有“临时生命周期”。 6.2.4/8 指的是从函数中按值返回的结构体(例如foo().x = 5; @m.m.:是的,由于 chux 对复合文字是左值的有用观察,我发现了这一点。因此,非左值数组文字是不可能的,因为函数不能返回数组。 (此外,复合文字不能是 VLA,因此它们的生命周期可以从块的开头开始。)

以上是关于如何使用复合文字来“fprintf()”具有任意基数的多个格式化数字?的主要内容,如果未能解决你的问题,请参考以下文章

复合文字使用无键字段

如何在不使用复合文字的情况下从标量初始化 AltiVec 寄存器

Qt 2D绘图之三:绘制文字路径图像复合模式

保护数组内容复合文字

如何使用引号包发出具有非十进制基数的整数文字?

可变参数模板