将__func__视为字符串文字而不是预定义的标识符
我正在使用gcc编译C99代码。 我想写一个宏,它将返回一个包含函数名和行号的字符串。
这就是我所拥有的:
#define INFO_MSG __FILE__ ":"__func__"()"
但是,当我编译试图使用此字符串的代码时,例如:
char buff[256] = {'\0'} sprintf(buff, "Something bad happened here: %s, at line: %d", INFO_MSG, __LINE__); printf("INFO: %s\n", buff);
我收到以下错误消息:
error: expected ')' before '__func__'
我已将问题跟踪到宏。 当我从宏中删除__func__
时,代码正确编译。
如何修复宏,以便我可以在字符串中包含预定义的__func__
宏?
从你的评论来看,目标是有一个宏,它将文件名和函数名(以及行号)组合成一个字符串,可以作为参数传递给printf()
或strcpy()
或syslog()
等printf()
syslog()
。
不幸的是,我不认为这是可能的。
C11标准说:
ISO / IEC 9899:2011§6.4.2.2 预定义标识符
¶1标识符
__func__
应由翻译者隐式声明,就像紧跟在每个函数定义的__func__
括号之后的声明一样static const char __func__[] = "function-name";
出现了,其中function-name是词法封闭函数的名称。
因此,与__FILE__
或__LINE__
不同, __func__
不是宏。
相关问题__PRETTY_FUNCTION__
, __FUNCTION__
__PRETTY_FUNCTION__
, __FUNCTION__
__func__
之间有什么区别? 涵盖一些替代名称。 这些是GCC特定的扩展,而不是标准名称。 此外,GCC 4.8.1文档说:
这些标识符不是预处理器宏。 在GCC 3.3及更早版本中,仅在C中,
__FUNCTION__
和__PRETTY_FUNCTION__
被视为字符串文字; 它们可以用于初始化char数组,它们可以与其他字符串文字连接。 GCC 3.4及更高版本将它们视为变量,如__func__
。 在C ++中,__FUNCTION__
和__PRETTY_FUNCTION__
一直是变量。
有充分理由说明为什么这些不能成为预处理器构造。 预处理器不知道函数是什么以及它正在处理的文本是否在函数的范围内,或者封闭函数的名称是什么。 它是一个简单的文本处理器,而不是编译器。 显然,可以在预处理器中建立这么多的理解(仅用于支持这一特性),但标准并不要求它,标准也不需要它。
不幸的是,我认为这意味着尝试将__func__
(通过任何拼写)与__FILE__
和__LINE__
在一个宏中以生成单个字符串文字是注定的。
显然,您可以使用标准的两步宏机制将文件名和行号生成为字符串:
#define STR(x) #x #define STRINGIFY(x) STR(x) #define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)
但是,您无法将函数名称作为字符串文字的一部分。
有论点认为文件名和行号足以识别问题所在; function名称几乎是必需的。 它更具有化妆品而非function性,对程序员有所帮助,但对其他用户没有帮助。
经过快速实验后,我发现你不能将__func__
用于字符串化。 如果可以的话,这没有多大意义,因为这意味着该值将是定义宏而不是应用宏的位置。
本答案中描述了__func__
的性质,正如对该问题的评论中所述。
字符串化是在预处理器时执行的,因为__func__
不可用,因为它本质上是一个函数本地字符串,稍后在编译过程中定义。
但是,只要不对其使用字符串化,就可以在宏中使用__func__
。 我认为以下内容可以满足您的需求:
#include #define INFO_MSG "Something bad happened here: %s : %s(), at line: %d", \ __FILE__, __func__, __LINE__ int main() { char buff[256] = {'\0'}; sprintf(buff, INFO_MSG); printf("INFO: %s\n", buff); return 0; }
请注意,在提出的问题中,使用字符串缓冲区没有特别的原因。 以下main
function可以实现相同的效果,而不会出现缓冲区溢出:
int main() { printf("INFO: "); printf(INFO_MSG); printf("\n"); return 0; }
就个人而言,我将在宏中完成整个过程,如下所示:
#include #define INFO_MSG(msg) printf("%s: %s : %s(), at line: %d\n", \ 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: %s\n", buff );
…请注意,可以在函数内部调用__func__
。 看到这个 。
这是一个语法错误。 我尝试过你的宏规范,但我找不到有效的方法,所以也许你可以试试这个:
#define INFO_MSG __FILE__ , __FUNCTION__ int main() { char buff[256] = {'\0'}; sprintf(buff, "Something bad happened here: %s : %s(), at line: %d", INFO_MSG, __LINE__); printf("INFO: %s\n", buff); }