将_func__视为字符串文字而不是预定义的标识符
我正在使用gcc编译C99代码。我想写一个宏,它将返回一个包含函数名和行号的字符串 这就是我所拥有的:将_func__视为字符串文字而不是预定义的标识符,c,macros,C,Macros,我正在使用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", bu
#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__’
我已将问题追溯到宏。当我从宏中删除\uuu func\uu
时,代码编译正确
如何修复宏,以便在字符串中包含预定义的
\uuuu func\uuu
宏?这是一个语法错误。我试图提供您的宏规范,但我没有找到有效的方法,因此您可以尝试以下方法:
#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);
}
经过一个快速的实验,我发现您不能将
\uuuuu func\uuuu
与字符串化一起使用。如果可以的话,这没有多大意义,因为这意味着该值将位于定义宏的任何位置,而不是应用宏的位置
如对问题的评论中所述,\uuuu func\uuu
的性质如中所述
字符串化是在预处理器时间执行的,因此\uuuu func\uuu
不可用,因为它本质上是一个函数本地字符串,稍后在编译过程中定义
但是,只要不在宏上使用字符串化,就可以在宏中使用\uuuu func\uu
。我认为以下是你所追求的:
#include <stdio.h>
#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;
}
就我个人而言,我会将整个过程概括为如下:
#include <stdio.h>
#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;
}
#包括
#定义信息\u MSG(MSG)printf(“%s:%s:%s(),第%d行\n”\
消息,文件,函数,行)
int main()
{
信息(“发生了不好的事情”);
返回0;
}
请注意,“\uuuuu func\uuuu>不是函数,因此无法调用它;事实上,它是一个预定义的标识符,指向作为函数名称的字符串,并且仅在函数范围内有效。”-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 );
。。。请注意,可以在函数本身内部调用\uuu func\uu
。请参阅。根据您的评论判断,目标是使宏将文件名和函数名(可能还有行号)组合成一个字符串,可以作为参数传递给函数,如printf()
或strcpy()
或syslog()
不幸的是,我认为这是不可能的
C11标准规定:
ISO/IEC 9899:2011§6.4.2.2预定义标识符
¨1翻译人员应隐式声明标识符\uuuu func\uuuu
,如同在每个函数定义的左括号后立即声明
static const char __func__[] = "function-name";
出现,其中function name是词汇封闭函数的名称
因此,\uuuuuu func\uuuuu
与\uuuuu文件或\uuuu行不同,它不是宏
相关问题涉及一些备选名称。这些是特定于GCC的扩展,而不是标准名称。此外,GCC 4.8.1文件规定:
这些标识符不是预处理器宏。在GCC 3.3及更早版本中,仅在C语言中,\uuuuuuuuuuuuu函数
和\uuuuuuuuu漂亮的函数
被视为字符串文字;它们可以被使用
初始化字符数组,它们可以与其他字符串文字连接。海湾合作委员会
3.4和更高版本将其视为变量,如\uuuu func\uuu
。在C++中,<>代码>函数> <代码> >代码>函数>函数>代码>始终是变量。< /P>
有充分的理由说明为什么这些不能成为预处理器结构。预处理器不知道函数是什么,也不知道它正在处理的文本是否在函数范围内,或者封闭函数的名称是什么。它是一个简单的文本处理器,而不是编译器。显然,在预处理器中建立这样的理解是可能的(仅仅是为了支持这一特性),但是标准不要求这样做,标准也不应该这样做
然而,不幸的是,我认为这意味着试图将\uuuu func\uuu
(通过任何拼写)与\uuuu FILE\uuu
和\uuu LINE\uuuu
组合在单个宏中以生成单个字符串文字的尝试都是注定要失败的
显然,您可以使用标准的两步宏机制将文件名和行号生成为字符串:
#define STR(x) #x
#define STRINGIFY(x) STR(x)
#define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)
但是,您不能将函数名作为字符串文本的一部分放入其中
有人认为文件名和行号足以确定问题所在;函数名几乎不需要。与其说是功能性的,不如说是装饰性的。它对程序员有点帮助,但对其他用户没有帮助。使用编译器的扩展器开关来查看输出的内容。我不相信\uuuu func\uu
是一个宏。也许你可以把INFO\u MSG
改为格式字符串<代码>sprintf(buff,“这里发生了一些不好的事情:%s:%s(),在第%d行“,”文件“,”函数“,”行“代码>@leppie:你能澄清一下吗你说的扩展器是什么意思?。顺便说一句,我使用的是gcc。@tangrs:\uuu func\uu
是C99(AFAIK)中预定义的宏。在gcc 4.2.1中似乎不是宏<代码>echo“const char*test(){return\uuuu func\uuu;}”| gcc-xc-E-std=c99-
显示const char*test(){return\uuu func\uuu;}
。编辑:显然。确实,您需要在函数本身内部使用\uuuuu func\uuuu
,但您可以先对其进行预处理。\uuu FILE\uuuu
已经是一个字符串;它不需要严格化\uuu func\uu
不是函数,因此无法调用;事实上,它是一个预定义的标识符,指向作为函数名称的字符串,并且仅在函数范围内有效。@JonathanLeffler,修复了答案--感谢您提供了丰富的后续信息。您可以使用通常的两阶段t
#define STR(x) #x
#define STRINGIFY(x) STR(x)
#define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)