为了调试目的,我能否在 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__);
__LINE__-1
吗? - Toby#define S1(N) #N
#define S2(N) S1(N)
#define LINESTR S2(__LINE__)
。请参阅http://c-faq.com/ansi/stringize.html。 - Rasmus Kaj__func__
不是宏,而是一个隐式声明的变量。 - HolyBlackCat__LINE__
宏,其中包括其他内容。
因此,您的代码将是:
__LINE__
: 当前源代码行的行号(一个十进制常量)。
__FILE__
: 源文件的假定名称(一个字符串字面值)。
__DATE__
: 源文件翻译的日期(一个字符串字面值...)
__TIME__
: 源文件翻译的时间(一个字符串字面值...)
__STDC__
: 是否预定义了__STDC__
。
__cplusplus
: 编译C++翻译单元时,名称__cplusplus
被定义为值199711L。
if(!Logical)
printf("Not logical value at line number %d \n",__LINE__);
__LINE__
这样的宏存在一个问题,就是如果你想创建一个输出当前行号和消息的日志函数,你总是需要将__LINE__
作为函数参数传递,因为它在调用点被展开。
类似于这样的代码:void log(const std::string msg) {
std::cout << __LINE__ << " " << msg << std::endl;
}
将始终输出函数声明的行,而不是实际调用log
的行。
另一方面,使用std::source_location
,您可以这样写:
#include <source_location>
#include <iostream>
void log(const char* msg, const std::source_location loc = std::source_location::current())
{
std::cout << loc.line() << " " << msg << std::endl;
}
int main() {
log ("test"); // Will print "10 test"
}
loc
被初始化为指向调用log
的位置所在的行号。
您可以在此处在线尝试。
在较旧的编译器版本中,std::source_location
可能只能作为std::experimental::source_location
访问。你可以使用一个宏来实现与 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 堆栈跟踪的信息。以下是一个示例 main 函数:
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()语法:字符串 = foobar,整数 = 42
main(main.cpp:13) 成功!
#include
更改为<stdio.h>
。 - phyatt使用__LINE__
(即双下划线 LINE 双下划线), 预处理器会将其替换为所在行的行号。
检查__FILE__
和__LINE__
宏
__FILE__
和__LINE__
。__DATE__
和__TIME__
有用。原始代码
(像这样:`__`)。@mmyers试图帮助,但他只转义了一个下划线,因此您留下了斜体的标记语法。尽管如此,对此进行负投票有点过分,我同意。 - mbauman针对可能需要的人,提供“FILE_LINE”宏以便轻松打印文件和行号:
#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
由于我现在也面临这个问题,而且无法回答一个不同但同样有效的问题这里,我将提供一个解决方案的示例: 使用模板仅获取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语言中,要打印__LINE__
,需要使用匹配的格式说明符:"%d"
。但在C++中使用cout
则不需要考虑这个问题。
严谨的问题:如果行号超过了INT_MAX
1(在16位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()
为了避免所有整数限制:使用字符串化。代码可以直接打印而不需要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()
相比。