как получить номер строки ошибки в программе на C ++

Я хочу обрабатывать ошибки в своей программе на 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
  }

}

В этом примере я могу получить только номер LINE B, но я хочу получить номера LINE A и LINE C.

Есть идеи, где и как использовать макрос LINE ??

Спасибо.


person CHAKRI    schedule 30.12.2010    source источник
comment
Вам нужна трассировка стека / трассировка.   -  person    schedule 30.12.2010
comment
decompile.com/cpp/faq/file_and_line_error_string.htm   -  person anno    schedule 31.12.2010


Ответы (5)


Вы ищете трассировку стека, но нет портативного способа ее получить. Нечто похожее может быть достигнуто с помощью:

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). Если это необходимо только во время тестирования (а не в производственной среде), вероятно, вам следует просто включить дампы ядра и научиться запускать отладчик в посмертном анализе.

person 6502    schedule 30.12.2010

Вам нужна трассировка стека и отладчик. В Стандартном C ++ нет возможности найти строку C, не передав ее в качестве аргумента (f(-6, __LINE__)), и вообще нет возможности найти строку A.

person Puppy    schedule 30.12.2010
comment
+1, но я бы назвал трассировку стека или отладчиком, поскольку трассировку стека можно получить даже без внешнего отладчика (см., Например, функцию backtrace). - person Matteo Italia; 30.12.2010

Строка C была бы почти невозможной (я не могу придумать способ ... кроме передачи второго аргумента в f, __LINE__.

Строка А выглядит следующим образом:

void f(int i){ const int lineA = __LINE__;
  if(i<0)
    throw(OutOfRange("message", __LINE__); // LINE B
}
person rubenvb    schedule 30.12.2010
comment
вы имеете в виду void f (int i) {const int lineA = LINE; if (i ‹0) throw (OutOfRange (message, lineA); // СТРОКА B} - person CHAKRI; 30.12.2010
comment
спасибо за ваш ответ, но я думаю, что LINE C не невозможно, потому что большинство компиляторов используют его !! - person CHAKRI; 30.12.2010
comment
@CHAKRI: компилятор может делать много, много, много вещей, которые вы не можете сделать в стандартном C ++. - person Puppy; 30.12.2010

В структуре CPPUNit вместо функций используются макросы. Таким образом, вы можете легко получить номер строки в том же месте, где вызывается макрос.

Я не думаю, что это правильный подход в общем смысле, но вам может быть интересно взглянуть на то, как это сделали разработчики CPPUnit.

person Antonio Pérez    schedule 30.12.2010
comment
+1. Посмотрите на реализацию макроса assert (); Я создал аналогичный макрос assertion (), который выдает исключение std :: logic_error вместо вызова std :: abort () при сбое утверждения. - person Raedwald; 30.12.2010

Помимо __LINE__, вы также можете использовать __func__ и __FILE__, чтобы предоставить вам дополнительную информацию. __func__ выдаст вам строку A, и вы можете, по крайней мере, получить строку внутри catch-блока, перебросив оттуда, но я не знаю другого способа получить строку C.


Вероятно, это поможет вам создать трассировку с использованием стандартного C ++ 11, то есть кроссплатформенного и без необходимости в отладчике или громоздком журналировании. За годы, прошедшие после того, как был задан этот вопрос, в C ++ были добавлены некоторые полезные функции. Вы можете отследить стек вызовов, который привел к исключению, используя:

std::nested_exception и _ 7_

Это описано на StackOverflow здесь и здесь

Однако для этого потребуется вставить операторы try/catch в функции, которые вы хотите отслеживать (т.е. функции без этого не будут отображаться в вашей трассировке). Вы можете автоматизировать это с помощью макросов, уменьшив объем кода, который вам нужно написать / изменить.

Поскольку вы можете сделать это с любым производным классом исключений, вы можете добавить много информации в такую ​​трассировку! Вы также можете взглянуть на мой MWE на GitHub, где обратная трассировка может что-то нравится:

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"
person GPMueller    schedule 24.12.2019