【问题标题】:Stringification of a macro value宏值的字符串化
【发布时间】:2011-02-08 20:09:59
【问题描述】:

我遇到了一个问题 - 我需要将宏值用作字符串和整数。

 #define RECORDS_PER_PAGE 10

 /*... */

 #define REQUEST_RECORDS \
      "SELECT Fields FROM Table WHERE Conditions" \
      " OFFSET %d * " #RECORDS_PER_PAGE \
      " LIMIT " #RECORDS_PER_PAGE ";"

 char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];

 /* ...and some more uses of RECORDS_PER_PAGE, elsewhere... */

这会失败并显示有关“stray #”的消息,即使它有效,我想我也会得到字符串化的宏名称,而不是值。当然,我可以将值提供给最终方法("LIMIT %d ", page*RECORDS_PER_PAGE),但它既不美观也不高效。 在这种情况下,我希望预处理器不以特殊方式处理字符串,而是像处理普通代码一样处理它们的内容。 目前,我将其与#define RECORDS_PER_PAGE_TXT "10" 联系在一起,但可以理解的是,我对此并不满意。

如何做到正确?

【问题讨论】:

标签: c string concatenation c-preprocessor


【解决方案1】:

下面定义的xstr 宏将在进行宏扩展后进行字符串化。

#define xstr(a) str(a)
#define str(a) #a

#define RECORDS_PER_PAGE 10

#define REQUEST_RECORDS \
    "SELECT Fields FROM Table WHERE Conditions" \
    " OFFSET %d * " xstr(RECORDS_PER_PAGE) \
    " LIMIT " xstr(RECORDS_PER_PAGE) ";"

【讨论】:

  • 这是最近的要求吗?我不记得上次我使用字符串化时需要这些技巧......
  • 如需进一步参考,可在gcc.gnu.org/onlinedocs/cpp/Stringification.html 获得有关字符串化 (GNU CPP) 机制(和细微差别)的更多描述。
  • 这个文档引用向我解释了它:“There is no way to combine an argument with surrounding text and stringize it all together. Instead, you can write a series of adjacent string constants and stringized arguments.
  • @VictorSergienko:这不是什么新鲜事,也没有什么害处——字符串文字连接,char* abc = "A" "B" "C"; 在所有方面都等同于char* abc = "ABC"; 这里的诀窍是如何获得字符串化的等价物,"B" 'B'B
【解决方案2】:
#include <stdio.h>

#define RECORDS_PER_PAGE 10

#define TEXTIFY(A) #A

#define _REQUEST_RECORDS(OFFSET, LIMIT)                 \
        "SELECT Fields FROM Table WHERE Conditions"     \
        " OFFSET %d * " TEXTIFY(OFFSET)                 \
        " LIMIT " TEXTIFY(LIMIT) ";"

#define REQUEST_RECORDS _REQUEST_RECORDS(RECORDS_PER_PAGE, RECORDS_PER_PAGE)

int main() {
        printf("%s\n", REQUEST_RECORDS);
        return 0;
}

输出:

SELECT Fields FROM Table WHERE Conditions OFFSET %d * 10 LIMIT 10;

注意对 _REQUEST_RECORDS 的间接性,以便在对参数进行字符串化之前对其进行评估。

【讨论】:

    【解决方案3】:

    尝试双重转义你的引号

    #define RECORDS_PER_PAGE 10
    #define MAX_RECORD_LEN 10
    
     /*... */
    #define DOUBLEESCAPE(a) #a
    #define ESCAPEQUOTE(a) DOUBLEESCAPE(a)
    #define REQUEST_RECORDS \
          "SELECT Fields FROM Table WHERE Conditions" \
          " OFFSET %d * " ESCAPEQUOTE(RECORDS_PER_PAGE)       \
          " LIMIT " ESCAPEQUOTE(RECORDS_PER_PAGE) ";"
    
     char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];
    
    int main(){
      char * a = REQUEST_RECORDS;
    }
    

    为我编译。令牌RECORDS_PER_PAGE 将被ESCAPEQUOTE 宏调用扩展,然后发送到DOUBLEESCAPE 以被引用。

    【讨论】:

    • 但它并没有替换正确的值,因为 # 的内容没有首先被评估。
    • @Mike 忘记了双重转义
    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 2019-06-21
    相关资源
    最近更新 更多