如何对作为宏操作结果的宏进行字符串化?

发布于 2024-11-30 12:04:58 字数 916 浏览 2 评论 0原文

这是一个说明我的问题的程序:

#include <stdio.h>

#define NUMERATOR 8
#define DENOMINATOR 2
#define QUOTIENT (NUMERATOR / DENOMINATOR)

#define ZSTR(x) XSTR(#x)
#define YSTR(x) XSTR(x)
#define XSTR(x) STR(x)
#define STR(x) #x

int main()
{
    printf("QUOTIENT:       %d\n", QUOTIENT);
    printf("STR(QUOTIENT):  %s\n", STR(QUOTIENT));
    printf("XSTR(QUOTIENT): %s\n", XSTR(QUOTIENT));
    printf("YSTR(QUOTIENT): %s\n", YSTR(QUOTIENT));
    printf("ZSTR(QUOTIENT): %s\n", ZSTR(QUOTIENT));
    return 0;
}

这是它的输出:

$ gcc -g -Wall -o stringify stringify.c && ./stringify 
QUOTIENT:       4
STR(QUOTIENT):  QUOTIENT
XSTR(QUOTIENT): (8 / 2)
YSTR(QUOTIENT): (8 / 2)
ZSTR(QUOTIENT): "QUOTIENT"

我希望将字符串文字 "4" 传递给编译器,但我失去了希望。 这与此问题相关,但增加了一个级别。

Here's a program that illustrates my problem:

#include <stdio.h>

#define NUMERATOR 8
#define DENOMINATOR 2
#define QUOTIENT (NUMERATOR / DENOMINATOR)

#define ZSTR(x) XSTR(#x)
#define YSTR(x) XSTR(x)
#define XSTR(x) STR(x)
#define STR(x) #x

int main()
{
    printf("QUOTIENT:       %d\n", QUOTIENT);
    printf("STR(QUOTIENT):  %s\n", STR(QUOTIENT));
    printf("XSTR(QUOTIENT): %s\n", XSTR(QUOTIENT));
    printf("YSTR(QUOTIENT): %s\n", YSTR(QUOTIENT));
    printf("ZSTR(QUOTIENT): %s\n", ZSTR(QUOTIENT));
    return 0;
}

And here's its output:

$ gcc -g -Wall -o stringify stringify.c && ./stringify 
QUOTIENT:       4
STR(QUOTIENT):  QUOTIENT
XSTR(QUOTIENT): (8 / 2)
YSTR(QUOTIENT): (8 / 2)
ZSTR(QUOTIENT): "QUOTIENT"

I would like to have a the string literal "4" passed to the compiler, but I'm losing hope.
This is related to this question, but adds a level.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

红衣飘飘貌似仙 2024-12-07 12:04:58

您可以定义将其参数粘贴在一起的宏,然后定义(大量)其他宏,这些宏以表查找的方式进行评估:

#define DIV(X, Y)  DIV_(X, Y)
#define DIV_(X, Y) DIV_##X##_##Y
#define DIV_0_1  0
#define DIV_1_1  1
#define DIV_2_1  2
    :
#define DIV_8_2  4
    :

这有点乏味,但您可以轻松编写一个小程序来生成头文件包含上述内容并将其作为构建过程的一部分运行。那么你只需要

#define QUOTIENT  DIV(NUMERATOR, DENOMINATOR)

注意,他的这种东西只适用于无符号整数——如果你需要负数或浮点数,它就不起作用

You can define macros that paste together their arguments and then define a (large) number of other macros that do the evaluation as kind of a table lookup:

#define DIV(X, Y)  DIV_(X, Y)
#define DIV_(X, Y) DIV_##X##_##Y
#define DIV_0_1  0
#define DIV_1_1  1
#define DIV_2_1  2
    :
#define DIV_8_2  4
    :

This is kind of tedious, but you can easily write a little program to generate a header file with the above stuff in it and run that as part of your build process. Then you just need

#define QUOTIENT  DIV(NUMERATOR, DENOMINATOR)

Note that his kind of thing only works for unsigned integers -- if you need negative numbers or floating point, it won't work

小兔几 2024-12-07 12:04:58

通过一些技巧,您可以在符合 C99 的预处理器中实现基本算术。 P99 实现十进制数的算术和逻辑。例如,

P99_IF_GT(1,0)(true)(false)
P99_ADD(3, 7)
P99_MUL(7, 2)
P99_DIV(7, 2)

可以将其预处理为类似的内容

1
10
14
3

。这些宏可以进一步处理、字符串化以及您喜欢的任何内容。

P99_STRINGIFY(P99_PASTE2(XXX_, P99_ADD(3, 7)))

预处理结果为 “XXX_10”

With some tricks you can implement basic arithmetic in a C99 conforming preprocessor. P99 implements arithmetic and logic for small decimal numbers. E.g

P99_IF_GT(1,0)(true)(false)
P99_ADD(3, 7)
P99_MUL(7, 2)
P99_DIV(7, 2)

would be preprocessed to something like

1
10
14
3

These macros can be processed further, stringified and everthing you like.

P99_STRINGIFY(P99_PASTE2(XXX_, P99_ADD(3, 7)))

leads to "XXX_10" as the result of preprocessing.

十雾 2024-12-07 12:04:58

你能做的最好的事情就是 stringify 宏的扩展,这是用你的XSTRYSTR 示例。尽管它可能通过优化编译为 4,但所有预处理器将能够看到的是 (8 / 2)

The best you can do is stringify the expansion of the macro which is done with your XSTR and YSTR examples. Although it may compile to 4 with optimizations all the preprocessor will be able see is (8 / 2)

烟柳画桥 2024-12-07 12:04:58

好吧,我有点不愿意承认我知道一种方法来完成这项工作。

从另一个方向攻击它。你希望你的编译器看到这样的东西。

#define QUOTIENT 4
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

既然宏处理器无法帮助我们,那么我们如何在 QUOTIENT 的定义中不使用文字“4”的情况下做到这一点呢?通过使用额外的预处理器。编写一个源文件 stringify.c.awk,如下所示。

/* stringify.c.awk --  Source file for stringify.c  
   (Put build instructions here.)  
 */
#define QUOTIENT NUMERATOR/DENOMINATOR
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

用 awk 编写辅助预处理器。我故意使用了非常严格的正则表达式。我认为如果源文件发生更改,它是最有可能失败的正则表达式,而且我认为这通常就是您想要的。 (我通常不希望对 #define 进行修饰性更改。)

# stringify.awk -- calculate and substitute the value for #define QUOTIENT.
BEGIN {
  NUMERATOR = 8;
  DENOMINATOR = 2;
}
{
  if ($0~/^#define QUOTIENT NUMERATOR\/DENOMINATOR$/) {
    sub(/NUMERATOR\/DENOMINATOR/, NUMERATOR/DENOMINATOR);
  } 
  print $0;
}

现在您可以从 stringify.c.awk 文件构建 stringify.c。

$ awk -f stringify.awk stringify.c.awk > stringify.c
$ gcc -Wall -o stringify stringify.c
$ ./stringify
QUOTIENT:       4

一个 makefile 和慷慨的注释可以消除很多痛苦。

(m4 没有帮助的原因或多或少与 C 预处理器没有帮助的原因相同。)

Well, I'm a little reluctant to admit I know one way to make this work.

Attack it from the other direction. You want your compiler to see something like this.

#define QUOTIENT 4
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

How do we do that without using a literal "4" in the definition of QUOTIENT, since the macro processor won't help us? By using an additional preprocessor. Write a source file, stringify.c.awk, like this.

/* stringify.c.awk --  Source file for stringify.c  
   (Put build instructions here.)  
 */
#define QUOTIENT NUMERATOR/DENOMINATOR
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

Write the secondary preprocessor in awk. I deliberately used a really tight regular expression. I think it's the most likely regex to fail if there are changes to the source file, and I think that's usually what you want. (I usually want to discourage cosmetic changes to the #define.)

# stringify.awk -- calculate and substitute the value for #define QUOTIENT.
BEGIN {
  NUMERATOR = 8;
  DENOMINATOR = 2;
}
{
  if ($0~/^#define QUOTIENT NUMERATOR\/DENOMINATOR$/) {
    sub(/NUMERATOR\/DENOMINATOR/, NUMERATOR/DENOMINATOR);
  } 
  print $0;
}

Now you can build stringify.c from the stringify.c.awk file.

$ awk -f stringify.awk stringify.c.awk > stringify.c
$ gcc -Wall -o stringify stringify.c
$ ./stringify
QUOTIENT:       4

A makefile and generous comments takes a lot of the pain away.

(m4 won't help for more or less the same reasons the C preprocessor won't help.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文