【问题标题】:How do I stringify macros that are the results of operations on macros?如何对作为宏操作结果的宏进行字符串化?
【发布时间】:2011-10-30 21:04:46
【问题描述】:

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

#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" 传递给编译器,但我失去了希望。 这与this question相关,但增加了一个级别。

【问题讨论】:

  • 我不认为你可以这样做...... # 运算符适用于预处理器令牌而不是表达式,所以如果没有办法做到这一点,我一点也不感到惊讶无论如何。
  • @Spudd86:是的,我只是希望有一种方法可以在预处理器中进行数学运算,并且这里有人会知道。
  • 你可以在预处理器中做数学运算,你只是不能将结果字符串化 #if 0 == 1 - 1 将导致 true
  • @Spudd86:好的,所以我希望有一种方法可以让我使用预处理器中的数学计算结果。也许我应该#if QUOTIENT != 4 #error

标签: c string macros c-preprocessor


【解决方案1】:

您可以定义将它们的参数粘贴在一起的宏,然后定义(大量)其他执行评估的宏作为一种表查找:

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

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

【讨论】:

  • 我感觉这很像 Jens 的建议,但更暴露了丑陋的一面。
【解决方案2】:

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

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"

【讨论】:

  • 你让我对想要预处理器为我做这些事情感到难过。 (不?)幸运的是,如果不重写所有构建脚本,我就无法为此使用符合 C99 的预处理器。
  • 实际上,您只需要一个符合 C89 的预处理器就可以从 P99 执行这种逐宏粘贴的操作。其他 P99 的东西需要 C99
  • @Chris,这大量使用了__VA_ARGS__,不是吗?这是 C99 的一项功能。许多编译器将其作为对 C89 的扩展来实现,P99 实现使用了规定的参数评估顺序的所有技巧,因此他们最好完全实现 C99 的那部分。
  • 原谅我的无知...P99_ADD 和朋友们的尸体在哪里?
  • @jww,你到底想知道什么? P99的来源在哪里?
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    #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 和丰富的 cmets 可以消除很多痛苦。

    (m4 无济于事,原因与 C 预处理器无济于事。)

    【讨论】:

    • 哇,这就像我们在编写软件时不应该做的事情的竞赛。我会在文档中修复它。 +1 表示不情愿。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-09
    • 2022-07-06
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    相关资源
    最近更新 更多