Использование __FILE__, __LINE__ и __FUNCTION__ в C ++

158

Предположив , что ваш компилятор C ++ поддерживает их, есть ли конкретная причина не в использовании __FILE__, __LINE__и __FUNCTION__для регистрации и целей отладки?

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

В принципе, я могу доверять __FILE__, __LINE__и __FUNCTION__чтобы всегда делать правильные вещи?

Runcible
источник
ЛИНИЯ должна делать правильные вещи. Я широко использовал его и его когорты, включая PRETTY_FUNCTION . ... но ... ну, я просто сейчас смотрю на код, где лежит LINE . Возможно, потому что он находится в блоке catch для обработки исключений try / catch.
Крейзи Глеу
4
релевантный: ссылка на gcc для предопределенных макросов
Александр Малахов

Ответы:

191

__FUNCTION__не является стандартным, __func__существует в C99 / C ++ 11. Остальные ( __LINE__и __FILE__) просто в порядке.

Он всегда сообщит правильный файл и строку (и функцию, если вы решите использовать __FUNCTION__/ __func__). Оптимизация не является фактором, так как это расширение макроса во время компиляции; это никак не повлияет на производительность.

Эван Теран
источник
3
__func__это своего рода проблема в C ++. C99 не говорит ни слова об аргументах по умолчанию и т. Д., В случаях, когда не так очевидно, как __func__вести себя в C ++.
wilhelmtell
4
@thr: пока вы делаете хорошую мысль. Мне было совершенно ясно, что __func__существует в C99, а не C ++. Несмотря на это, я думаю, что разумная реализация __func__в c ++ просто приведет к искаженному имени. Поскольку я не пишу компилятор, это не совсем мой вызов.
Эван Теран
Какие компиляторы вообще не поддерживаются __FUNCTION__? Какие компиляторы кроме недавнего gcc рассматривают это как переменную, а не макрос?
бассейн
36
__func__сейчас в стандарте C ++ 11.
VX
38

В редких случаях может быть полезно изменить строку, заданную __LINE__чем-то другим. Я видел, что GNU configure делает это для некоторых тестов, чтобы сообщать соответствующие номера строк после того, как он вставил вуду между строками, которые не отображаются в исходных исходных файлах. Например:

#line 100

Следующие строки будут начинаться с __LINE__100. При желании вы можете добавить новое имя файла

#line 100 "file.c"

Это редко полезно. Но если это необходимо, я не знаю альтернатив. На самом деле, вместо строки можно использовать макрос, который должен приводить к любой из двух вышеуказанных форм. Используя библиотеку препроцессора boost, вы можете увеличить текущую строку на 50:

#line BOOST_PP_ADD(__LINE__, 50)

Я думал, что это полезно упомянуть, так как вы спросили об использовании __LINE__и __FILE__. Никто никогда не получает достаточно сюрпризов из C ++ :)

Редактировать: @Джонатан Леффлер приводит еще несколько хороших примеров использования в комментариях:

Работа с #line очень полезна для препроцессоров, которые хотят, чтобы ошибки сообщались в коде C пользователя в соответствии с его исходным файлом. Yacc, Lex и (больше дома для меня) препроцессоры ESQL / C делают это.

Йоханнес Шауб - Литб
источник
29

К вашему сведению: g ++ предлагает нестандартный макрос __PRETTY_FUNCTION__. До сих пор я не знал о C99 __func__ (спасибо, Эван!). Я думаю, что я все еще предпочитаю __PRETTY_FUNCTION__, когда это доступно для дополнительного определения класса.

PS:

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}
Mr.Ree
источник
2
Приятно знать о __PRETTY_FUNCTION__. Очень полезно!
Чжэн Цюй
8

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

Крейг С
источник
29
«Я мог бы записать эту информацию на консоль» - или еще лучше: записать ее в файл, чтобы, если что-то пошло не так, вы могли попросить клиента отправить ее вам ...
Кристоф
7

C ++ 20 std::source_location

В C ++ наконец-то добавлена ​​опция не-макросов, и она, вероятно, будет доминировать в будущем, когда C ++ 20 станет широко распространенным:

Документация гласит:

constexpr const char * function_name () const noexcept;

6 Returns: Если этот объект представляет позицию в теле функции, возвращает NTBS, определенный реализацией, который должен соответствовать имени функции. В противном случае возвращает пустую строку.

где NTBS означает «строка байтов, завершенная нулем».

Я попробую, когда поддержка придет в GCC, GCC 9.1.0 g++-9 -std=c++2aвсе еще не поддерживает его.

https://en.cppreference.com/w/cpp/utility/source_location утверждает, что использование будет следующим:

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int main() {
    log("Hello world!");
}

Возможный вывод:

info:main.cpp:16:main Hello world!

__PRETTY_FUNCTION__против __FUNCTION__против __func__противstd::source_location::function_name

Ответили по адресу: В чем разница между __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
1
Есть <experimental/source_location>в текущем gcc-9.
陈浩南
5

Я использую их все время. Единственное, о чем я беспокоюсь, это выдача IP в лог-файлах. Если ваши имена функций действительно хороши, возможно, вам будет проще раскрыть коммерческую тайну. Это похоже на доставку с отладочными символами, только труднее найти вещи. В 99,999% случаев ничего плохого из этого не выйдет.

JeffCharter
источник
1
Хорошая точка для воспитания. Извлечь эту информацию тривиально, используя stringsутилиту для извлечения всех строковых данных из исполняемого файла. Даже сжатые исполняемые файлы могут быть извлечены. Будьте очень внимательны к тому, что вы отправляете на сайт клиента. Часто конкуренты могут получить в свои руки исполняемые файлы, даже если они не должны этого делать.
Марти
Это возможно с constexpr, который использует таблицу поиска или побитовый XOR и т. Д., Чтобы скрыть любые строковые литералы в вашем двоичном файле. Существуют различные примеры, если вы ищете. Конечно, запутывание - это просто запутывание, а не безопасность, но если вы не хотите, чтобы ваши файлы и функции были очевидны в двоичном виде, это вариант.
иди