如何在C++程序中获取错误行号

13

我希望在我的C++程序中处理错误,所以我创建了一些异常类来管理这些错误,但我想指定在程序的哪一行发生了错误。

我将LINE宏传递给我的异常类构造函数。

例如:

void f(int i){ // LINE A
  if(i<0)
    throw(OutOfRange("message", __LINE__); // LINE B
}

void main(){

  try{
    f(-6); // LINE C
  }
  catch(const OutOfRange& error){
    //do something
  }

}
在这个例子中,我只能获取线B的编号,但我想获取线A和线C的编号。有什么想法,在哪里以及如何使用LINE宏吗?谢谢。

1
你想要一个堆栈跟踪/回溯。 - user395760
http://www.decompile.com/cpp/faq/file_and_line_error_string.htm - anno
5个回答

8

如果您想要查看堆栈跟踪,没有一种通用的方法可以获取它。不过,您可以通过以下方式实现类似的效果:

struct SourcePoint
{
    const char *filename;
    int line;
    SourcePoint(const char *filename, int line)
      : filename(filename), line(line)
    { }
};

std::vector<SourcePoint> callstack;

struct SourcePointMarker
{
    SourcePointMarker(const char *filename, int line)
    {
        callstack.push_back(SourcePoint(filename, line);
    }

    ~SourcePointMarker()
    {
        callstack.pop_back();
    }
}

#define MARK_FUNCTION \
  SourcePointMarker sourcepointmarker(__FILE__, __LINE__);

然后在每个函数(或重要点)的开头,只需添加一行代码...例如:

int myFunction(int x)
{
    MARK_FUNCTION
    ...
}

使用此方法在您的错误处理程序中,您可以知道是谁调用了谁等等(当然,您只会知道已使用MARK_FUNCTION进行仪器化的函数或位置)。如果这仅在测试期间需要(而不是在生产中),那么可能您应该只启用核心转储并学习如何在事后分析中运行调试器。


1

第 C 行几乎不可能(我想不到其他方法...除非通过向 f 传递第二个参数 __LINE__

第 A 行如下:

void f(int i){ const int lineA = __LINE__;
  if(i<0)
    throw(OutOfRange("message", __LINE__); // LINE B
}

你的意思是 void f(int i){ const int lineA = LINE; if(i<0) throw(OutOfRange("message", lineA ); // LINE B } - CHAKRI
谢谢您的回答,但我认为“LINE C”并不是不可能的,因为大多数编译器都使用它!! - CHAKRI
1
@CHAKRI:编译器可以做很多很多你在标准C++中无法做到的事情。 - Puppy

1
你需要一个堆栈跟踪和调试器。在标准C++中,如果没有将它作为参数传递(f(-6, __LINE__)),你无法找到行C的代码,也无法找到A行的代码。

我同意“堆栈跟踪或调试器”,因为即使没有外部调试器(例如,使用backtrace函数),也可以获取堆栈跟踪。所以应该选择其中一个即可。 - Matteo Italia

1

CPPUnit框架使用宏而不是函数。这样,您可以在调用宏的同一位置轻松获取行号。

我认为这不是一种通用的有效方法,但您可能会发现有兴趣了解CPPUnit开发人员的做法。


+1. 看一下 assert() 宏的实现;我创建了一个类似的 assertion() 宏,当断言失败时,它会抛出一个 std::logic_error 异常而不是调用 std::abort()。 - Raedwald

0
除了__LINE__之外,您还可以使用__func____FILE__来提供更多信息。 __func__将给出A行,您可以通过从那里重新抛出来至少获得catch块内的一行,但我不知道另一种获取C行的方法。

使用标准C++11创建回溯可能会对您有所帮助,即跨平台且无需调试器或繁琐的日志记录。

自提出此问题以来,C++已经添加了一些有用的功能。

您可以使用以下方法跟踪导致异常的调用堆栈:

std::nested_exceptionstd::throw_with_nested

在StackOverflow上有描述这里这里

但是,这将需要您在要跟踪的函数中插入try/catch语句(即没有此语句的函数将不会出现在跟踪中)。 您可以使用宏自动化此过程,从而减少您需要编写/更改的代码量。

由于您可以使用任何派生异常类来执行此操作,因此可以向这样的回溯中添加大量信息!您还可以查看我的GitHub上的MWE,其中回溯将类似于以下内容:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接