__FILE__, __LINE__ та __FUNCTION__ використання у C ++


158

Якщо припустити, що ваш компілятор C ++ підтримує їх, чи є якась причина не для використання __FILE__, __LINE__а __FUNCTION__для цілей реєстрації та налагодження?

Я в першу чергу переймаюся тим, щоб дати користувачам вводити в оману даних (наприклад, повідомити про неправильний номер рядка чи функції в результаті оптимізації) або взяти в результаті показник ефективності.

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


LINE повинна робити правильно. Я широко використовував його та його групи, включаючи PRETTY_FUNCTION . ... Але ... ну, я просто зараз дивлюсь на код, де лежить LINE . Можливо, тому, що він знаходиться в блоці вилову для обробки випробувань / вилову винятків.
Krazy Glew

Відповіді:


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 робить для деяких тестів повідомлення про відповідні номери рядків після того, як він вставив деякий вуду між рядками, які не відображаються в оригінальних вихідних файлах. Наприклад:

#line 100

Наступні рядки почнуться з __LINE__100. Ви можете додатково додати нове ім’я файлу

#line 100 "file.c"

Це корисно лише рідко. Але якщо це потрібно, я не знаю альтернатив. Насправді замість рядка також може бути використаний макрос, який повинен спричинити будь-яку з перелічених вище форм. Використовуючи бібліотеку препроцесора підвищення, ви можете збільшити поточний рядок на 50:

#line BOOST_PP_ADD(__LINE__, 50)

Я вважав, що це корисно згадати, оскільки ви запитали про використання __LINE__та __FILE__. Ніколи не отримує достатньо сюрпризів із С ++ :)

Редагувати: @Jonathan Leffler надає ще кілька корисних випадків використання у коментарях:

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


29

FYI: 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. */
}

2
Приємно знати про __PRETTY_FUNCTION__. Дуже корисний!
Чжен Ку

8

Особисто я не бажаю використовувати їх для нічого, крім повідомлень про налагодження. Я це зробив, але намагаюся не показувати таку інформацію клієнтам або кінцевим користувачам. Мої клієнти не є інженерами і іноді не підходять до комп'ютера. Я можу занести цю інформацію до консолі, але, як я вже сказав, неохоче, за винятком збірок налагоджень або для внутрішніх інструментів. Я думаю, це все ж залежить від клієнтської бази у вас.


29
"Я можу занести цю інформацію до консолі" - а ще краще: запишіть її у файл, щоб, якщо щось пішло не так, ви можете попросити клієнта надіслати його вам ...
Крістоф

7

C ++ 20 std::source_location

Нарешті, C ++ додав не-макро-варіант, і він, ймовірно, домінуватиме в якийсь момент у майбутньому, коли C ++ 20 набуде широкого поширення:

Документація говорить:

constexpr const char * function_name () const noexcept;

6 Повернення: Якщо цей об'єкт представляє позицію в тілі функції, повертає визначену реалізацією NTBS, яка повинна відповідати імені функції. В іншому випадку повертає порожній рядок.

де NTBS означає "Null Terminated Byte String".

Я спробую, коли підтримка надійде до 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__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Відповів на: Яка різниця між __PRETTY_FUNCTION__, __FUNCTION__, __func__?


1
Є <experimental/source_location>в поточному gcc-9.
陈浩南

5

Я їх постійно використовую. Єдине, про що я хвилююсь - це віддавати IP-файли в журналах. Якщо назви ваших функцій дійсно хороші, ви можете полегшити розкриття комерційної таємниці. Це на зразок доставки з символами налагодження, лише складніше знайти речі. У 99,999% випадків нічого поганого з цього не вийде.


1
Гарний момент виховувати. Витягнути цю інформацію за допомогою stringsутиліти нереально, щоб витягти всі рядкові дані з виконуваного файлу. Навіть стиснуті виконавчі файли можна витягти. Будьте дуже уважні до того, що ви надсилаєте на сайт клієнта. Часто конкуренти можуть потрапити на ваш виконуваний файл, навіть якщо вони цього не передбачають.
Марті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.