如何使用 __LINE__ 或其他方法从呼叫站点获取行号?
How to get the line number from the call site using __LINE__ or some other method?
考虑一下我写的这个短程序:
#include <iostream>
template<bool Debug = false>
constexpr int add(const int& a, const int& b) {
if (Debug)
std::cout << __FUNCTION__ << " called on line " << __LINE__ << '\n';
return (a + b);
}
int main() {
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9) << '\n';
return 0;
}
它工作得很好,并给出了正确的输出:
10
add called on line 6
14
但是,我希望打印的行号是程序调用站点的行,在这个程序中应该是第 12 行。
那么我如何使用 __LINE__
或其他一些方法来给我调用函数的行号?
所需的输出将是:
10
add called on line 12
14
如果可能的话,我希望它由函数本身生成。
-编辑-
作为对 reader 的说明,我对任何和所有选项都持开放态度,但我当前的构建环境仅限于 C++17,并且我正在使用 Visual Studio。
你可以这样称呼它:
template<bool Debug = false>
constexpr int add(const int& a, const int& b, int loc = __LINE__) {
if (Debug)
std::cout << __FUNCTION__ << " called on line " << loc << '\n';
return (a + b);
}
int main() {
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9, __LINE__) << '\n';
return 0;
}
输出:
10
add called on line 14
14
此外,您可以定义一个宏来跳过第三个参数:
#define add_Debug(a, b) add<true>(a,b,__LINE__)
C++ 20 及更高版本
在 C++20 中,我们得到 std::source_location
,其中包含有关行号、函数、文件名的信息。如果您的编译器支持它,您可以使用它。示例(使用 g++ 9.3.0 测试)。您将不再需要宏:
#include <iostream>
#include <experimental/source_location>
using source_location = std::experimental::source_location;
template<bool Debug = false>
constexpr int add(const int& a, const int& b, source_location l = source_location::current()) {
if (Debug)
// this will print 'main' as function name
//std::cout << l.function_name() << " called on line " << l.line() << //'\n';
std::cout << source_location::current().function_name() << " called on line " << l.line() << '\n';
return (a + b);
}
int main()
{
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9) << '\n';
return 0;
}
输出:
10
add<true> called on line 16
14
有了 source_location
,您就不必再使用宏了。它将正确打印行
如果您可以使用一些最近的 GCC (in July 2020, that means GCC 10), you might compile with g++ -g -O -Wall
then use Ian Taylor's libbacktrace (like we do in RefPerSys) since that library parses DWARF 调试信息在 Linux 上编译您的代码。
您可以将该库移植到您的操作系统和调试信息格式,或者找到一些等效的。
今天,一种更粗略的可能性是用宏包装一些函数。例如,不是用 void foo(void);
调用 foo()
,而是
extern void foo_at(const char*fileno, int lineno);
#define foo() foo_at(__FILE__,__LINE__);
确实,C++20 应该添加 feature tests and source_location
but you might need to wait a few months for a compiler supporting it. Consider compiling a recent GCC from its source code. AFAIK MinGW 64 在 Windows 上运行(因此请征得使用许可)。
考虑一下我写的这个短程序:
#include <iostream>
template<bool Debug = false>
constexpr int add(const int& a, const int& b) {
if (Debug)
std::cout << __FUNCTION__ << " called on line " << __LINE__ << '\n';
return (a + b);
}
int main() {
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9) << '\n';
return 0;
}
它工作得很好,并给出了正确的输出:
10
add called on line 6
14
但是,我希望打印的行号是程序调用站点的行,在这个程序中应该是第 12 行。
那么我如何使用 __LINE__
或其他一些方法来给我调用函数的行号?
所需的输出将是:
10
add called on line 12
14
如果可能的话,我希望它由函数本身生成。
-编辑-
作为对 reader 的说明,我对任何和所有选项都持开放态度,但我当前的构建环境仅限于 C++17,并且我正在使用 Visual Studio。
你可以这样称呼它:
template<bool Debug = false>
constexpr int add(const int& a, const int& b, int loc = __LINE__) {
if (Debug)
std::cout << __FUNCTION__ << " called on line " << loc << '\n';
return (a + b);
}
int main() {
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9, __LINE__) << '\n';
return 0;
}
输出:
10
add called on line 14
14
此外,您可以定义一个宏来跳过第三个参数:
#define add_Debug(a, b) add<true>(a,b,__LINE__)
C++ 20 及更高版本
在 C++20 中,我们得到 std::source_location
,其中包含有关行号、函数、文件名的信息。如果您的编译器支持它,您可以使用它。示例(使用 g++ 9.3.0 测试)。您将不再需要宏:
#include <iostream>
#include <experimental/source_location>
using source_location = std::experimental::source_location;
template<bool Debug = false>
constexpr int add(const int& a, const int& b, source_location l = source_location::current()) {
if (Debug)
// this will print 'main' as function name
//std::cout << l.function_name() << " called on line " << l.line() << //'\n';
std::cout << source_location::current().function_name() << " called on line " << l.line() << '\n';
return (a + b);
}
int main()
{
std::cout << add(3, 7) << '\n';
std::cout << add<true>(5, 9) << '\n';
return 0;
}
输出:
10
add<true> called on line 16
14
有了 source_location
,您就不必再使用宏了。它将正确打印行
如果您可以使用一些最近的 GCC (in July 2020, that means GCC 10), you might compile with g++ -g -O -Wall
then use Ian Taylor's libbacktrace (like we do in RefPerSys) since that library parses DWARF 调试信息在 Linux 上编译您的代码。
您可以将该库移植到您的操作系统和调试信息格式,或者找到一些等效的。
今天,一种更粗略的可能性是用宏包装一些函数。例如,不是用 void foo(void);
调用 foo()
,而是
extern void foo_at(const char*fileno, int lineno);
#define foo() foo_at(__FILE__,__LINE__);
确实,C++20 应该添加 feature tests and source_location
but you might need to wait a few months for a compiler supporting it. Consider compiling a recent GCC from its source code. AFAIK MinGW 64 在 Windows 上运行(因此请征得使用许可)。