编程参考 - C/C++中的方便调试使用的内置宏

本文介绍了C/C++编程中常用的标准预定义宏如__FILE__、__LINE__、__DATE__和__TIME__,以及GNUC扩展的__BASE_FILE__和__PRETTY_FUNCTION__,展示了如何通过这些宏快速获取文件名、行号、日期和时间,以及函数名称,提高调试效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当我们在调试代码时,经常需要打印log。这时就要输入函数名、文件名等信息,如果手动输入就很麻烦,每次都要输入不一样的内容。

而其实开发环境里里已经预定义了一些宏,方便我们使用。在预处理阶段,预处理器可以识别这些宏,简化我们的工作。

下面介绍标准的C/C++里面的一些相关预定义宏:

这个一般的C/C++编译器都会支持,如果太老的编译器则不一定支持。这些宏都是以双下划线开头。

Macro Name

Description

__FILE__

此宏的内容将被扩展成当前输入的准备处理的文件名,数据格式是一个C的字符串常量。这是一个文件路径名,预处理器用此路径打开要处理的源文件。注意不是#include所指定的文件名,那个是缩短版。而是一个符合操作系统规范的可访问文件路径,比如绝对路径:"/usr/local/include/test.c",或者相对路径,“./test.c”或“test.c”。实际上,其内容就是编译器接收的文件参数。

这个宏,只表示使用这个宏的文件名,比如一个头文件使用了这个宏,再被包含在另一个文件中,这个宏还是显示头文件的名字。

__LINE__

这个宏将展开为代码当前行数,是一个十进制表示的整型常量。这个宏的定义,会随着每行的代码所变化。

这个宏,只表示使用这个宏的文件内行数,比如一个头文件使用了这个宏,再被包含在另一个文件中,这个宏还是显示头文件中的行数。

使用#line指令可以更改__LINE__的定义,比如#line 100,就指定下一行的行号是100.

__DATE__

这个宏展开为一个表示预处理器处理此文件的日期,是一个字符串常量。

显示格式为:"Feb 12 1996",“Aug  3 2022”,一共11个字符,当月份小于10,左边用空格填充。

如果GCC不能确定当前日期,编译过程每遇到一次会发出一个警告,宏的内容显示为"??? ?? ????"。

__TIME__

这个宏展开为一个表示预处理器处理此文件的时间,是一个字符串常量。

显示格式为:"23:59:01”,一共8个字符。

如果GCC不能确定当前时间,编译过程每遇到一次会发出一个警告,宏的内容显示为"??:??:??"。

__func__

这个宏是C99所引入的,但很早以来GCC一直使用的是__FUNCTION__。这两个都是字符串常量,表示当前的函数名。

但实际上这两个宏并不是真正的宏,因为预处理器是不知道当前的函数名的。

下面是GNU C扩展所常用的预定义宏:

Macro Name

Description

__BASE_FILE__

这个宏展开得到输入文件的名称,是一个C语言字符串常量。和上面的__FILE__类似。

这是在预处理器或C编译器的命令行中指定的源文件,针对的一个编译单元的源代码文件。

比如你在test.c中,包含了一个test.h,则test.h里面使用此宏,显示的还是test.c这个文件名。

__FILE_NAME__

这个宏扩展为当前输入文件的基本名称,以C语言字符串常数的形式出现。这是预处理器打开文件的路径名的最后一部分。例如,处理"/usr/local/include/myheader.h "将把这个宏设置为 "myheader.h"。

但这个我用Ubuntu中的GCC试验,不可用,显示未定义。

函数名字的字符串

GCC提供了三个神奇的常量,将当前函数的名称作为一个字符串保存。在C++11及以后的版本中,这三个常量都被当作常量表达式,可以用在需使用constexpr的上下文中。这些常量中的第一个是__func__,它是C99标准的一部分:

标识符 __func__ 被翻译器隐含地声明,就像在每个函数定义的开口括号之后,紧接着声明:

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

其中 function-name 是语法上由两个大括号闭合的函数的名称。这个名字是函数的不加修饰的名字。作为扩展,在文件(或者在 C++ 的某个命名空间范围)中,__func__ 的值被定义为空字符串。

__FUNCTION__是__func__的另一个名字,是为了向后兼容旧版本的GCC而提供的。

在C语言中,__PRETTY_FUNCTION__是__func__的另一个名字,只是在文件范围内(或者在C++的某个命名空间范围内),它的值是字符串 "top level"。此外,在 C++ 中,__PRETTY_FUNCTION__ 包含了函数的签名和它的裸名。

比如:

extern "C" int printf (const char *, ...); 

class a { 

public: 

    void sub (int i) 

    { 

        printf ("__FUNCTION__ = %s\n", __FUNCTION__); 

        printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__); 

    } 

}; 

int main (void) 

    a ax; 

    ax.sub (0); 

    return 0; 

}

输出是:

__FUNCTION__ = sub 

__PRETTY_FUNCTION__ = void a::sub(int)


原版英文:

Standard Predefined Macros

The standard predefined macros are specified by the relevant language standards, so they are available with all compilers that implement those standards. Older compilers may not provide all of them. Their names all start with double underscores.

__FILE__

This macro expands to the name of the current input file, in the form of a C string constant. This is the path by which the preprocessor opened the file, not the short name specified in ‘#include’ or as the input file name argument. For example, "/usr/local/include/myheader.h" is a possible expansion of this macro.

__LINE__

This macro expands to the current input line number, in the form of a decimal integer constant. While we call it a predefined macro, it’s a pretty strange macro, since its “definition” changes with each new line of source code.

__FILE__ and __LINE__ are useful in generating an error message to report an inconsistency detected by the program; the message can state the source line at which the inconsistency was detected. For example,

fprintf (stderr, "Internal error: "

                 "negative string length "

                 "%d at %s, line %d.",

         length, __FILE__, __LINE__);

An ‘#include’ directive changes the expansions of __FILE__ and __LINE__ to correspond to the included file. At the end of that file, when processing resumes on the input file that contained the ‘#include’ directive, the expansions of __FILE__ and __LINE__ revert to the values they had before the ‘#include’ (but __LINE__ is then incremented by one as processing moves to the line after the ‘#include’).

A ‘#line’ directive changes __LINE__, and may change __FILE__ as well. See Line Control.

C99 introduced __func__, and GCC has provided __FUNCTION__ for a long time. Both of these are strings containing the name of the current function (there are slight semantic differences; see the GCC manual). Neither of them is a macro; the preprocessor does not know the name of the current function. They tend to be useful in conjunction with __FILE__ and __LINE__, though.

__DATE__

This macro expands to a string constant that describes the date on which the preprocessor is being run. The string constant contains eleven characters and looks like "Feb 12 1996". If the day of the month is less than 10, it is padded with a space on the left.

If GCC cannot determine the current date, it will emit a warning message (once per compilation) and __DATE__ will expand to "??? ?? ????".

__TIME__

This macro expands to a string constant that describes the time at which the preprocessor is being run. The string constant contains eight characters and looks like "23:59:01".

If GCC cannot determine the current time, it will emit a warning message (once per compilation) and __TIME__ will expand to "??:??:??".

Common Predefined Macros

The common predefined macros are GNU C extensions.

__BASE_FILE__

This macro expands to the name of the main input file, in the form of a C string constant. This is the source file that was specified on the command line of the preprocessor or C compiler.

__FILE_NAME__

This macro expands to the basename of the current input file, in the form of a C string constant. This is the last path component by which the preprocessor opened the file. For example, processing "/usr/local/include/myheader.h" would set this macro to "myheader.h".

6.50 Function Names as Strings

GCC provides three magic constants that hold the name of the current function as a string. In C++11 and later modes, all three are treated as constant expressions and can be used in constexpr constexts. The first of these constants is __func__, which is part of the C99 standard:

The identifier __func__ is implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

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

appeared, where function-name is the name of the lexically-enclosing function. This name is the unadorned name of the function. As an extension, at file (or, in C++, namespace scope), __func__ evaluates to the empty string.

__FUNCTION__ is another name for __func__, provided for backward compatibility with old versions of GCC.

In C, __PRETTY_FUNCTION__ is yet another name for __func__, except that at file scope (or, in C++, namespace scope), it evaluates to the string "top level". In addition, in C++, __PRETTY_FUNCTION__ contains the signature of the function as well as its bare name. For example, this program:

extern "C" int printf (const char *, ...);

class a {

public:

  void sub (int i)

    {

      printf ("__FUNCTION__ = %s\n", __FUNCTION__);

      printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);

    }

};

int

main (void)

{

  a ax;

  ax.sub (0);

  return 0;

}

gives this output:

__FUNCTION__ = sub

__PRETTY_FUNCTION__ = void a::sub(int)

These identifiers are variables, not preprocessor macros, and may not be used to initialize char arrays or be concatenated with string literals.

参考:

Function Names (Using the GNU Compiler Collection (GCC))

Top (The C Preprocessor)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜流冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值