c-将__func_视为字符串文字,而不是预定义的标识符



我正在使用gcc编译C99代码。我想写一个宏,它将返回一个包含函数名称和行号的字符串。

这就是我所拥有的:

#define INFO_MSG  __FILE__ ":"__func__"()"

然而,当我编译试图使用这个字符串的代码时,例如:

char buff[256] = {''}
sprintf(buff, "Something bad happened here: %s, at line: %d", INFO_MSG, __LINE__);
printf("INFO: %sn", buff);

我收到以下错误消息:

error: expected ‘)’ before ‘__func__’

我已经把问题归结到宏观层面。当我从宏中删除__func__时,代码编译正确。

如何修复宏,以便在字符串中包含预定义的__func__宏?

根据您的评论判断,目标是创建一个宏,将文件名和函数名(可能还有行号)组合成一个字符串,该字符串可以作为参数传递给printf()strcpy()syslog()等函数。

不幸的是,我认为这是不可能的。

C11标准规定:

ISO/IEC 9899:2011§6.4.2.2预定义标识符

¶1翻译器应隐式声明标识符__func__,就好像紧接在每个函数定义的大括号后面的声明

static const char __func__[] = "function-name";

出现,其中函数名称是词汇封闭函数的名称。

因此,与__FILE____LINE__不同,__func__不是宏。

相关问题__PRETTY_FUNCTION____FUNCTION____func__有什么区别?涵盖了一些备选名称。这些是GCC特定的扩展,而不是标准名称。此外,GCC 4.8.1文件规定:

这些标识符不是预处理器宏。在GCC 3.3及更早版本中,仅在C中,__FUNCTION____PRETTY_FUNCTION__被视为字符串文字;它们可以使用以初始化char数组,并且它们可以与其他字符串文字连接。GCC3.4,然后将它们视为变量,如__func__。在C++中,__FUNCTION____PRETTY_FUNCTION__一直是变量。

这些不能作为预处理器构造是有充分理由的。预处理器不知道函数是什么,不知道它正在处理的文本是否在函数的范围内,也不知道封闭函数的名称是什么。它是一个简单的文本处理器,而不是编译器。很明显,在预处理器中建立这么多理解是可能的(仅仅是为了支持这一特性),但这不是标准要求的,也不应该是标准要求的。

然而,不幸的是,我认为这意味着将__func__(通过任何拼写)与__FILE____LINE__组合在一个宏中以生成单个字符串文字的尝试都是注定要失败的。

显然,您可以使用标准的两步宏机制将文件名和行号生成为字符串:

#define STR(x) #x
#define STRINGIFY(x) STR(x)
#define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)

不过,您不能将函数名作为字符串文字的一部分。

有一些论点认为,文件名和行号足以确定问题所在;函数名称几乎没有必要。与其说是功能性的,不如说是外观性的,它对程序员有一些帮助,但对其他用户没有帮助。

经过快速实验,我发现不能将__func__与字符串化一起使用。如果可以的话,这将没有多大意义,因为这意味着该值将位于定义宏的位置,而不是应用宏的位置。

正如对该问题的评论中所指出的,__func__的性质在本答复中有所描述。

字符串化是在预处理器时执行的,因此__func__不可用,因为它本质上是一个函数本地字符串,稍后在编译过程中定义。

然而,你可以在宏中使用__func__,只要你不在它上使用字符串化

#include <stdio.h>
#define INFO_MSG "Something bad happened here: %s : %s(), at line: %d", 
                 __FILE__, __func__, __LINE__
int main()
{
    char buff[256] = {''};
    sprintf(buff, INFO_MSG);
    printf("INFO: %sn", buff);
    return 0;
}

请注意,在所提出的问题中,使用字符串缓冲区并没有什么特别的原因。以下main功能将在没有缓冲区溢出可能性的情况下实现相同的效果:

int main()
{
    printf("INFO: ");
    printf(INFO_MSG);
    printf("n");
    return 0;
}

就我个人而言,我会把整个过程总结成这样的宏:

#include <stdio.h>
#define INFO_MSG(msg) printf("%s: %s : %s(), at line: %dn", 
                        msg, __FILE__, __func__, __LINE__)
int main()
{
    INFO_MSG("Something bad happened");
    return 0;
}

注意,"__func__不是函数,因此无法调用;事实上,它是一个预定义的标识符,指向函数名称字符串,并且仅在函数范围内有效。"-Jonathan。

以下是您正在寻找的:

#define TO_STR_A( A ) #A
#define TO_STR( A ) TO_STR_A( A )
#define INFO_MSG TO_STR( __LINE__ ) ":" __FILE__
char buff[ 256 ] = { 0 };
sprintf( buff, "Something bad happened here, %s in function %s().", INFO_MSG, __func__ );
printf( "INFO: %sn", buff );

请注意,可以在函数本身内部调用CCD_ 27。看看这个。

这是一个语法错误。我试着提出你的宏规范,但我没有找到有效的方法,所以也许你可以试试这个:
#define INFO_MSG  __FILE__ , __FUNCTION__   
int main()
{
    char buff[256] = {''};
    sprintf(buff, "Something bad happened here: %s : %s(), at line: %d", INFO_MSG, __LINE__);
    printf("INFO: %sn", buff);
}

最新更新