将_func__视为字符串文字而不是预定义的标识符

将_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

我正在使用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__’
我已将问题追溯到宏。当我从宏中删除
\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__)