C/C++行号

Bet*_*moo 102 c c++ dynamic-compilation line-numbers c-preprocessor

出于调试目的,我可以在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)
Run Code Online (Sandbox Code Playgroud)

Jul*_*rau 166

您应该使用预处理器宏__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__);
Run Code Online (Sandbox Code Playgroud)

  • C99使用\ _ _ _ func\_\_而不是\ _ _ _ FUNCTION\_ _ _,部分弃用AFAIK.差异可能会破坏您的代码,因为\ _ _ _ func\_\_不能用于C的常量字符串连接. (2认同)
  • @sep332是的,但是cpp是一个奇怪的野兽,所以它必须用宏参数分两步完成。`#define S1(N) #N` `#define S2(N) S1(N)` `#define LINESTR S2(__LINE__)` 。请参阅http://c-faq.com/ansi/stringize.html (2认同)
  • 严格来说,`__func__`不是一个宏,它是一个隐式声明的变量。 (2认同)

Bri*_*ndy 62

作为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__);
Run Code Online (Sandbox Code Playgroud)


Som*_*mer 19

您可以使用与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)
Run Code Online (Sandbox Code Playgroud)

这些宏应该与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!");
}
Run Code Online (Sandbox Code Playgroud)

这导致以下输出:

main(main.cpp:11)在exampleMethod()之前...
exampleMethod(main.cpp:7)printf()语法:string = foobar,int = 42
main(main.cpp:13)成功!


mea*_*gar 11

使用__LINE__(这是双下划线LINE双下划线),预处理器将用它遇到的行号替换它.


小智 9

结帐__FILE____LINE__


sir*_*ain 9

C++20 通过使用std::source_location提供了一种新方法来实现这一点。这是目前在海湾合作委员会的铛可访问std::experimental::source_location#include <experimental/source_location>

宏的问题__LINE__是,如果你想创建例如一个输出当前行号和消息的日志函数,你总是必须__LINE__作为函数参数传递,因为它在调用站点被扩展。像这样的东西:

void log(const std::string msg) {
    std::cout << __LINE__ << " " << msg << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

将始终输出函数声明的行而不是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;
}
Run Code Online (Sandbox Code Playgroud)

在这里,loc用指向log调用位置的行号初始化。 您可以在此处在线试用。


San*_*099 5

尝试__FILE____LINE__
您可能还会发现__DATE__并且__TIME__有用。
不过,除非您必须在客户端调试程序并因此需要记录这些信息,否则您应该使用正常调试。

  • @Sanctus2099 有些人很快就会投反对票,这就是为什么确保你的答案正确很重要。在这种情况下,您发布了错误的答案,并在 4 小时内未对其进行编辑。除了你自己,你没有人可以责怪。 (2认同)

cla*_*tfu 5

对于那些可能需要它的人,可以使用“FILE_LINE”宏轻松打印文件和行:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
Run Code Online (Sandbox Code Playgroud)