出于调试目的,我可以在C /C++ 编译器中获取行号吗?(某些编译器的标准方式或特定方式)
例如
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
出于调试目的,我可以在C /C++ 编译器中获取行号吗?(某些编译器的标准方式或特定方式)
例如
if(!Logical)
printf("Not logical value at line number %d \n",LineNumber);
// How to get LineNumber without writing it by my hand?(dynamic compilation)
您应该使用预处理器宏__LINE__
和__FILE__
. 它们是预定义的宏,是 C/C++ 标准的一部分。在预处理期间,它们分别被一个常量字符串替换,该字符串包含一个表示当前行号的整数和当前文件名。
其他预处理器变量:
__func__
: 函数名(这是C99的一部分,并非所有 C++ 编译器都支持它)__DATE__
: 形式为“Mmm dd yyyy”的字符串__TIME__
: 形式为“hh:mm:ss”的字符串您的代码将是:
if(!Logical)
printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);
作为 C++ 标准的一部分,您可以使用一些预定义的宏。C++ 标准的第 16.8 节定义了__LINE__
宏。
__LINE__
:当前源行的行号(十进制常量)。
__FILE__
:源文件的假定名称(字符串文字)。
__DATE__
:源文件的翻译日期(字符串文字...)
__TIME__
:源文件的翻译时间(字符串文字...)
__STDC__
:是否__STDC__
预定义
__cplusplus
:名称__cplusplus
定义为值 199711L 时编译一个 C++ 翻译单元
所以你的代码是:
if(!Logical)
printf("Not logical value at line number %d \n",__LINE__);
您可以使用与printf()具有相同行为的宏,除了它还包含调试信息,例如函数名称、类和行号:
#include <cstdio> //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a, __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)
这些宏的行为应该与printf()相同,同时包含类似 java stacktrace 的信息。这是一个主要的示例:
void exampleMethod() {
println("printf() syntax: string = %s, int = %d", "foobar", 42);
}
int main(int argc, char** argv) {
print("Before exampleMethod()...\n");
exampleMethod();
println("Success!");
}
这导致以下输出:
main(main.cpp:11) 之前 exampleMethod()...
exampleMethod(main.cpp:7) printf() 语法: string = foobar, int = 42
main(main.cpp:13) 成功!
使用__LINE__
(即双下划线 LINE 双下划线),预处理器会将其替换为遇到的行号。
C++20 提供了一种通过使用std::source_location来实现此目的的新方法。这目前可以在 gcc 和 clang 中访问,std::experimental::source_location
如#include <experimental/source_location>
.
像这样的宏的问题__LINE__
是,如果您想创建例如一个输出当前行号和消息的日志记录函数,您总是必须__LINE__
作为函数参数传递,因为它在调用站点被扩展。像这样的东西:
void log(const std::string msg) {
std::cout << __LINE__ << " " << msg << std::endl;
}
将始终输出函数声明的行,而不是log
实际调用的行。另一方面,std::source_location
你可以这样写:
#include <experimental/source_location>
using std::experimental::source_location;
void log(const std::string msg, const source_location loc = source_location::current())
{
std::cout << loc.line() << " " << msg << std::endl;
}
在这里,loc
用指向log
被调用位置的行号进行初始化。
你可以在这里在线尝试。
结帐__FILE__
和__LINE__
宏
对于那些可能需要它的人,一个“FILE_LINE”宏可以轻松打印文件和行:
#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
尝试__FILE__
和__LINE__
。
您可能还会发现__DATE__
和__TIME__
有用。
尽管除非您必须在客户端调试程序并因此需要记录这些信息,否则您应该使用正常调试。
由于我现在也面临这个问题,我无法为这里提出的不同但有效的问题添加答案,我将为以下问题提供一个示例解决方案:仅获取调用函数的行号C++ 使用模板。
背景:在 C++ 中,可以使用非类型整数值作为模板参数。这与将数据类型用作模板参数的典型用法不同。所以想法是使用这样的整数值进行函数调用。
#include <iostream>
class Test{
public:
template<unsigned int L>
int test(){
std::cout << "the function has been called at line number: " << L << std::endl;
return 0;
}
int test(){ return this->test<0>(); }
};
int main(int argc, char **argv){
Test t;
t.test();
t.test<__LINE__>();
return 0;
}
输出:
该函数已在行号调用:0
该函数已在第 16 行调用
这里要提到的一件事是,在 C++11 标准中,可以为使用模板的函数提供默认模板值。在 C++11 之前,非类型参数的默认值似乎只适用于类模板参数。因此,在 C++11 中,不需要像上面那样重复函数定义。在 C++11 中,具有 const char* 模板参数也是有效的,但不能将它们与此处__FILE__
提到的或__func__
如前所述的文字一起使用。
所以最后,如果你使用 C++ 或 C++11,这可能是一个非常有趣的替代方案,而不是使用宏来获取调用行。
使用__LINE__
,但它的类型是什么?
LINE当前源代码行(一个整数常量)的假定行号(在当前源文件中)。
作为一个整数常量,代码通常可以假设值是__LINE__ <= INT_MAX
,类型是 int
。
要在 C 中打印,printf()
需要匹配说明符:"%d"
. 在带有cout
.
迂腐的担忧:如果行号超过INT_MAX
1(在 16-bit 中可以想象到int
),希望编译器会产生警告。例子:
format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]
或者,代码可以强制使用更广泛的类型来阻止此类警告。
printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));
避免printf()
为了避免所有整数限制:stringify。代码无需调用即可直接打印printf()
:在错误处理中避免的一件好事2。
#define xstr(a) str(a)
#define str(a) #a
fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);
1拥有如此大的文件当然是糟糕的编程实践,但机器生成的代码可能会很高。
2在调试中,有时代码根本无法按预期工作。*printf()
与简单的fputs()
.