在C语言的printf字符串中使用宏?

sh7euo9m  于 2023-02-03  发布在  其他
关注(0)|答案(2)|浏览(178)

给定3个双精度值x,y和z,我会进行很多这样的printf调用:

printf("[%+-8.3lf, %+-8.3lf, %+-8.3lf]\n", x, y, z);

然后,我希望有一个某种类型的宏来编写如下内容:

#define FORMAT(x,y) "+-x.ylf"

printf("[%FORMAT(8,3), %FORMAT(8,3), %FORMAT(8,3)]\n", a->x, a->y, a->z);

但是当然,编译器把%F看作一个特殊的字符串,并且没有把我的宏放到字符串里面。有什么方法可以达到我想要的效果吗?

bnl4lu3b

bnl4lu3b1#

使用简单数字作为FORMAT的参数

您的“类似这样的东西”代码很接近--但是您需要使用字符串连接(相邻字符串的文字)和#操作符来“字符串化”宏参数:

#define FORMAT(x,y) "%+-" #x "." #y "lf"

printf("[" FORMAT(8,3) ", " FORMAT(8,3) ", " FORMAT(8,3) "]\n",
       a->x, a->y, a->z);

这类似于使用<inttypes.h>中的宏来打印int64_t之类的类型,不同之处在于,您必须提供%符号(以及任何标志):

uint64_t x = 0x43218765CBA9;
printf("x = 0x%.12" PRIX64 "\n", x);

使用宏作为FORMAT的参数

有没有办法把8和3也定义为宏呢?比如,我不想到处写FORMAT(8,3),我想把FORMAT(X, Y)写在我上面定义的#define X 8#define Y 3上。
是的,有一种方法可以做到这一点。引入一个额外的宏:

#define STR(z) #z

并在FORMAT的参数上调用该函数,如下所示:

/* SO 7531-4669 */
#include <stdio.h>

#define STR(z)  #z
#define FORMAT(x,y) "%+-" STR(x) "." STR(y) "lf"

#define Y 4
#define X 8

struct Point { double x, y, z; };

int main(void)
{
    struct Point b = { 7123.4567, 6234.5678, 5345.6789 };
    struct Point *a = &b;

    printf("[" FORMAT(X, Y) ", " FORMAT(X, Y) ", " FORMAT(X, Y) "]\n",
           a->x, a->y, a->z);

    printf("[" FORMAT(8, 3) ", " FORMAT(8, 3) ", " FORMAT(8, 3) "]\n",
           a->x, a->y, a->z);

    return 0;
}

这将运行并生成以下输出:

[+7123.4567, +6234.5678, +5345.6789]
[+7123.457, +6234.568, +5345.679]

它演示了可以使用简单数字或Map到简单数字的宏作为FORMAT宏的参数,但不能使用#define Y 3#define X (Y + 6)-这将字符串化在printf()转换规范中无效的(3 + 6)。你可以在你的数字和下面的逗号之间加上空格。用#define X 12来实验一下,看看我的意思。)
调用另一个宏的技术会触发参数的扩展,这通常是您想要的。请参见How to make a char string from a C macro's value?Macro directives in C — my code example doesn't workHow can I concatenate twice with the C preprocessor and expand a macro as in " arg ## _ ## MACRO "?的问答是关于标记串联而不是字符串化的,但问题是密切相关的,解决方案也是相似的。

q7solyqu

q7solyqu2#

您可以将宏调整为类似于:

#define SPEC "lf"
#define FORMAT(x, y) "+-"#x"."#y SPEC

并调用printf

printf("%"FORMAT(3, 20), x)

%放在宏中也可能是一个好主意。
单个散列(#),* 将 * x和y参数“转换”为字符串常量。
Example

相关问题