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

时间:2021-10-07 06:51:32

I am trying to use a function-like macro to generate an object-like macro name (generically, a symbol). The following will not work because __func__ (C99 6.4.2.2-1) puts quotes around the function name.

我试图使用类似函数的宏来生成类似对象的宏名称(通常是一个符号)。以下内容不起作用,因为__func __(C99 6.4.2.2-1)在函数名称周围加上引号。

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

The desired result of calling MAKE_AN_IDENTIFIER(NULL_POINTER_PASSED) would be MyFunctionName__NULL_POINTER_PASSED. There may be other reasons this would not work (such as __func__ being taken literally and not interpreted, but I could fix that) but my question is what will provide a predefined macro like __func__ except without the quotes? I believe this is not possible within the C99 standard so valid answers could be references to other preprocessors.

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

Presently I have simply created my own object-like macro and redefined it manually before each function to be the function name. Obviously this is a poor and probably unacceptable practice. I am aware that I could take an existing cpp program or library and modify it to provide this functionality. I am hoping there is either a commonly used cpp replacement which provides this or a preprocessor library (prefer Python) which is designed for extensibility so as to allow me to 'configure' it to create the macro I need.

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


I wrote the above to try to provide a concise and well defined question but it is certainly the Y referred to by @Ruud. The X is...

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

I am trying to manage unique values for reporting errors in an embedded system. The values will be passed as a parameter to a(some) particular function(s). I have already written a Python program using pycparser to parse my code and identify all symbols being passed to the function(s) of interest. It generates a .h file of #defines maintaining the values of previously existing entries, commenting out removed entries (to avoid reusing the value and also allow for reintroduction with the same value), assigning new unique numbers for new identifiers, reporting malformed identifiers, and also reporting multiple use of any given identifier. This means that I can simply write:

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

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

    // do something actually interesting here
}

and the Python program will create the #define MYFUNC_NULL_POINTER_PASSED 7 (or whatever next available number) for me with all the listed considerations. I have also written a set of macros that further simplify the above to:

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

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

    // do something actually interesting here
}

assuming I provide the #define FUNC. I want to use the function name since that will be constant throughout many changes (as opposed to LINE) and will be much easier for someone to transfer the value from the old generated #define to the new generated #define when the function itself is renamed. Honestly, I think the only reason I am trying to 'solve' this 'issue' is because I have to work in C rather than C++. At work we are writing fairly object oriented C and so there is a lot of NULL pointer checking and IsInitialized checking. I have two line functions that turn into 30 because of all these basic checks (these macros reduce those lines by a factor of five). While I do enjoy the challenge of crazy macro development, I much prefer to avoid them. That said, I dislike repeating myself and hiding the functional code in a pile of error checking even more than I dislike crazy macros.

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

If you prefer to take a stab at this issue, have at.

如果您想更好地解决这个问题,请参加。

3 个解决方案

#1


1  

Gnu-C has a __FUNCTION__ macro, but sadly even that cannot be used in the way you are asking.

Gnu-C有一个__FUNCTION__宏,但遗憾的是,即使不能按照你要求的方式使用它。

#2


1  

__FUNCTION__ used to compile to a string literal (I think in gcc 2.96), but it hasn't for many years. Now instead we have __func__, which compiles to a string array, and __FUNCTION__ is a deprecated alias for it. (The change was a bit painful.)

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

But in neither case was it possible to use this predefined macro to generate a valid C identifier (i.e. "remove the quotes").

但是在这两种情况下都不可能使用这个预定义的宏来生成有效的C标识符(即“删除引号”)。

But could you instead use the line number rather than function name as part of your identifier?

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

If so, the following would work. As an example, compiling the following 5-line source file:

如果是这样,以下将起作用。例如,编译以下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);

will generate the warning:

将生成警告:

foo.c:5: warning: 'line_5__NULL_POINTER_PASSED' defined but not used

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

#3


1  

As pointed out by others, there is no macro that returns the (unquoted) function name (mainly because the C preprocessor has insufficient syntactic knowledge to recognize functions). You would have to explicitly define such a macro yourself, as you already did yourself:

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

#define FUNC MYFUNC

To avoid having to do this manually, you could write your own preprocessor to add the macro definition automatically. A similar question is this: How to automatically insert pragmas in your program

为避免必须手动执行此操作,您可以编写自己的预处理器以自动添加宏定义。类似的问题是:如何在程序中自动插入编译指示

If your source code has a consistent coding style (particularly indentation), then a simple line-based filter (sed, awk, perl) might do. In its most naive form: every function starts with a line that does not start with a hash or whitespace, and ends with a closing parenthesis or a comma. With awk:

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

{
    print $0;
}

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

For a more robust solution, you need a compiler framework like ROSE.

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

#1


1  

Gnu-C has a __FUNCTION__ macro, but sadly even that cannot be used in the way you are asking.

Gnu-C有一个__FUNCTION__宏,但遗憾的是,即使不能按照你要求的方式使用它。

#2


1  

__FUNCTION__ used to compile to a string literal (I think in gcc 2.96), but it hasn't for many years. Now instead we have __func__, which compiles to a string array, and __FUNCTION__ is a deprecated alias for it. (The change was a bit painful.)

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

But in neither case was it possible to use this predefined macro to generate a valid C identifier (i.e. "remove the quotes").

但是在这两种情况下都不可能使用这个预定义的宏来生成有效的C标识符(即“删除引号”)。

But could you instead use the line number rather than function name as part of your identifier?

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

If so, the following would work. As an example, compiling the following 5-line source file:

如果是这样,以下将起作用。例如,编译以下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);

will generate the warning:

将生成警告:

foo.c:5: warning: 'line_5__NULL_POINTER_PASSED' defined but not used

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

#3


1  

As pointed out by others, there is no macro that returns the (unquoted) function name (mainly because the C preprocessor has insufficient syntactic knowledge to recognize functions). You would have to explicitly define such a macro yourself, as you already did yourself:

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

#define FUNC MYFUNC

To avoid having to do this manually, you could write your own preprocessor to add the macro definition automatically. A similar question is this: How to automatically insert pragmas in your program

为避免必须手动执行此操作,您可以编写自己的预处理器以自动添加宏定义。类似的问题是:如何在程序中自动插入编译指示

If your source code has a consistent coding style (particularly indentation), then a simple line-based filter (sed, awk, perl) might do. In its most naive form: every function starts with a line that does not start with a hash or whitespace, and ends with a closing parenthesis or a comma. With awk:

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

{
    print $0;
}

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

For a more robust solution, you need a compiler framework like ROSE.

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