【问题标题】:How to make a char string from a C macro's value?如何从 C 宏的值生成 char 字符串?
【发布时间】:2010-09-16 19:04:40
【问题描述】:

例如,如何避免两次写入'func_name'?

#ifndef TEST_FUN
#  define TEST_FUN func_name
#  define TEST_FUN_NAME "func_name"
#endif

我想遵循Single Point of Truth 规则。

C 预处理器版本:

$ cpp --version
cpp (GCC) 4.1.2 20070626 (Red Hat 4.1.2-14)

【问题讨论】:

标签: c c-preprocessor dry


【解决方案1】:

He who is Shy* 给了你answer 的胚芽,但只有胚芽。在 C 预处理器中将值转换为字符串的基本技术确实是通过 '#' 运算符,但建议解决方案的简单音译会导致编译错误:

#define TEST_FUNC test_func
#define TEST_FUNC_NAME #TEST_FUNC

#include <stdio.h>
int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

语法错误出现在“puts()”行 - 问题是源代码中的“杂散#”。

在 C 标准的第 6.10.3.2 节“# 运算符”中,它说:

每个 # 预处理标记 类似函数的替换列表 宏后面应该跟一个参数 作为下一个预处理令牌 替换列表。

问题在于您可以将宏参数转换为字符串——但您不能转换非宏参数的随机项。

所以,要达到你想要的效果,你肯定需要做一些额外的工作。

#define FUNCTION_NAME(name) #name
#define TEST_FUNC_NAME  FUNCTION_NAME(test_func)

#include <stdio.h>

int main(void)
{
    puts(TEST_FUNC_NAME);
    return(0);
}

我不完全清楚您打算如何使用宏,以及您打算如何完全避免重复。这个稍微复杂一点的例子可能会提供更多信息。使用与 STR_VALUE 等效的宏是获得所需结果所必需的惯用语。

#define STR_VALUE(arg)      #arg
#define FUNCTION_NAME(name) STR_VALUE(name)

#define TEST_FUNC      test_func
#define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC)

#include <stdio.h>

static void TEST_FUNC(void)
{
    printf("In function %s\n", TEST_FUNC_NAME);
}

int main(void)
{
    puts(TEST_FUNC_NAME);
    TEST_FUNC();
    return(0);
}

* 在第一次写这个答案时,shoosh 的名字使用了“害羞”作为名字的一部分。

【讨论】:

  • 它有效。谢谢你。我发布了一个反映代码动机的工作示例。 stackoverflow.com/questions/195975/…
  • 几乎逐字重写了最初于 2012 年 10 月 12 日 21:37 发表的评论(显示的是粗体 func 而不是 __func__)——当然,在 C99 中,我们可以在函数中使用__func__ 预定义标识符来表示函数名。然而,这在函数之外没有任何帮助,这才是真正需要函数名字符串的地方。
  • 您的第二个代码对我不起作用。 test_func 我认为应该是 OP 案例的宏。如果你把#define test_func my_test_func. (从而使 test_func 成为宏),它仍然打印 test_func 而不是 my_test_func
  • @ChanKim:你能说明什么不起作用吗?如果需要(如果它不适合评论),请通过电子邮件与我联系 - 请参阅我的个人资料。
  • @JonathanLeffler 你好,我给你发了一封电子邮件。我们需要两级宏替换。见stackoverflow.com/questions/3419332/…
【解决方案2】:

@Jonathan Leffler:谢谢。您的解决方案有效。

一个完整的工作示例:

/** compile-time dispatch 

   $ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
*/
#include <stdio.h>

#define QUOTE(name) #name
#define STR(macro) QUOTE(macro)

#ifndef TEST_FUN
#  define TEST_FUN some_func
#endif

#define TEST_FUN_NAME STR(TEST_FUN)

void some_func(void)
{
  printf("some_func() called\n");
}

void another_func(void)
{
  printf("do something else\n");
}

int main(void)
{
  TEST_FUN();
  printf("TEST_FUN_NAME=%s\n", TEST_FUN_NAME);
  return 0;
}

例子:

$ gcc -Wall -DTEST_FUN=another_func macro_sub.c -o macro_sub && ./macro_sub
do something else
TEST_FUN_NAME=another_func

【讨论】:

    【解决方案3】:
    #include <stdio.h>
    
    #define QUOTEME(x) #x
    
    #ifndef TEST_FUN
    #  define TEST_FUN func_name
    #  define TEST_FUN_NAME QUOTEME(TEST_FUN)
    #endif
    
    int main(void)
    {
        puts(TEST_FUN_NAME);
        return 0;
    }
    

    参考:维基百科的C preprocessor页面

    【讨论】:

      【解决方案4】:

      #define TEST_FUN_NAME #FUNC_NAME

      here

      【讨论】:

      • 这确实不正确 - 另请参阅我的回答。令人惊讶的是,它有 4 票赞成。问题是,如果你不仔细考虑的话,它看起来或多或少是正确的。
      猜你喜欢
      • 1970-01-01
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      • 2021-06-11
      • 1970-01-01
      • 2021-07-19
      • 1970-01-01
      • 2015-06-19
      相关资源
      最近更新 更多