如何在宏中将函数名称作为文本而不是字符串?

时间:2014-04-04 12:15:52

标签: c c-preprocessor

我正在尝试使用类似函数的宏来生成类似对象的宏名称(通常是符号)。以下操作无效,因为__func__C99 6.4.2.2-1)会在函数名称周围添加引号。

#define MAKE_AN_IDENTIFIER(x) __func__##__##x

调用MAKE_AN_IDENTIFIER(NULL_POINTER_PASSED)所需的结果为MyFunctionName__NULL_POINTER_PASSED。可能还有其他原因导致这种情况无效(例如__func__字面意义而不是解释,但我可以解决这个问题)但我的问题是什么会提供预定义的宏,如__func__除外没有引号?我认为这在C99标准中是不可能的,因此有效的答案可能是对其他预处理器的引用。

目前我只是创建了自己的类似对象的宏,并在每个函数作为函数名之前手动重新定义它。显然这是一种可怜的,可能是不可接受的做法。我知道我可以使用现有的cpp程序或库并对其进行修改以提供此功能。 我希望有一个常用的cpp替换提供这个或预处理器库(更喜欢Python),它是为可扩展性而设计的,这样我就可以“配置”它来创建我需要的宏。


我写了上面的内容,试图提供一个简洁明确的问题,但肯定是@Ruud提到的Y. X是......

我正在尝试管理嵌入式系统中报告错误的唯一值。这些值将作为参数传递给(某些)特定函数。我已经使用pycparser编写了一个Python程序来解析我的代码并识别传递给感兴趣的函数的所有符号。它生成一个.h #define个文件,保留以前存在的条目的值,注释掉已删除的条目(以避免重用该值并允许重新引入相同的值),为其分配新的唯一编号新标识符,报告格式错误的标识符,并报告任何给定标识符的多次使用。这意味着我可以简单地写:

void MyFunc(int * p)
{
    if (p == NULL)
    {
        myErrorFunc(MYFUNC_NULL_POINTER_PASSED);
        return;
    }

    // do something actually interesting here
}

并且Python程序将为我创建#define MYFUNC_NULL_POINTER_PASSED 7(或任何下一个可用的数字)以及所有列出的注意事项。我还编写了一组宏,进一步简化了上述内容:

#define FUNC MYFUNC
void MyFunc(int * p)
{
    RETURN_ASSERT_NOT_NULL(p);

    // do something actually interesting here
}

假设我提供了#define FUNC。我想使用函数名称,因为它会在很多变化中保持不变(而不是 LINE ),并且对于某人将旧的生成#define中的值传递给重命名函数本身时生成的新#define。老实说,我认为我试图“解决”这个“问题”的唯一原因是因为我必须使用C而不是C ++。在工作中,我们编写了相当面向对象的C,因此有很多NULL指针检查和IsInitialized检查。由于所有这些基本检查,我有两个行函数变为30(这些宏将这些行减少了五倍)。虽然我确实喜欢疯狂的宏观发展的挑战,但我更愿意避免它们。也就是说,我不喜欢重复自己并将功能代码隐藏在一堆错误检查中,甚至比不喜欢疯狂的宏还要多。

如果你想更好地解决这个问题,请点击。

3 个答案:

答案 0 :(得分:1)

Gnu-C有一个__FUNCTION__宏,但遗憾的是,即使这样也无法按照你要求的方式使用。

答案 1 :(得分:1)

__FUNCTION__ 使用编译为字符串文字(我认为在 gcc 2.96 ),但它已经很多年了。现在我们有__func__,它编译成字符串 array ,而__FUNCTION__是不推荐使用的别名。 (这种变化有点痛苦。)

但是在 情况下,是否可以使用此预定义宏来生成有效的C标识符(即“删除引号”)。

但您是否可以使用行号而不是函数名作为标识符的一部分?

如果是这样,以下内容将起作用。例如,编译以下5行源文件:

 #define CONCAT_TOKENS4(a,b,c,d)      a##b##c##d
 #define EXPAND_THEN_CONCAT4(a,b,c,d) CONCAT_TOKENS4(a,b,c,d)
 #define MAKE_AN_IDENTIFIER(x)        EXPAND_THEN_CONCAT4(line_,__LINE__,__,x)

 static int MAKE_AN_IDENTIFIER(NULL_POINTER_PASSED);

将生成警告:

  

foo.c:5:警告:'line_5__NULL_POINTER_PASSED'已定义但未使用

答案 2 :(得分:1)

正如其他人所指出的,没有宏返回(未引用的)函数名称(主要是因为C预处理器没有足够的语法知识来识别函数)。您必须自己明确定义这样一个宏,就像您自己做的那样:

#define FUNC MYFUNC

为避免必须手动执行此操作,您可以编写自己的预处理器以自动添加宏定义。类似的问题是:How to automatically insert pragmas in your program

如果您的源代码具有一致的编码样式(特别是缩进),那么可以使用简单的基于行的过滤器(sed,awk,perl)。最天真的形式:每个函数都以一个不以哈希或空格开头的行开头,并以一个右括号或逗号结束。使用 awk

{
    print $0;
}

/^[^# \t].*[,\)][ \t]*$/ {
    sub(/\(.*$/, "");
    sub(/^.*[ \t]/, "");
    print "#define FUNC " toupper($0);
}

对于更强大的解决方案,您需要一个像ROSE这样的编译器框架。