Предопределенные макросы для имени функции __func__
Я пытаюсь создать функцию сообщения журнала отладки, которая записывает файл, строку и функцию того, откуда вызывается сообщение журнала.
#define DEBUG_PANIC(p) CLogging::Debuglogf( "Debug marker (%s) - ::%s() in file: %s(%d)", p, __func__ , __FILE__, __LINE__ );
Вышеприведенный код работает с некоторыми компиляторами, но не со всеми. Мой код должен быть совместим с GCC, а также с Microsoft Visual studio. Я добавил следующие определения, чтобы помочь с совместимостью.
#ifndef __FUNCTION_NAME__
#if defined __func__
// Undeclared
#define __FUNCTION_NAME__ __func__
#elif defined __FUNCTION__
// Undeclared
#define __FUNCTION_NAME__ __FUNCTION__
#elif defined __PRETTY_FUNCTION__
// Undeclared
#define __FUNCTION_NAME__ __PRETTY_FUNCTION__
#else
// Declared
#define __FUNCTION_NAME__ "N/A"
#endif // __func__
#endif // __FUNCTION_NAME__
#define DEBUG_PANIC(p) CLogging::Debuglogf( "Debug marker (%s) - ::%s() in file: %s(%d)", p, __FUNCTION_NAME__, __FILE__, __LINE__ );
Проблема с приведенным выше фрагментом кода заключается в том, что макроС#else активен для всех компиляторов, а другие макросы - нет. другими словами #if defined __func__
является ложным в компиляторах, где __func__
- предопределенный макрос.
Мой вопрос
- Как создать макрос кросс-компилятора для поиска имени функции?
- Как узнать, можно ли использовать
__func__
?
Ответы
Ответ 1
Вы предполагаете, что __func__
- это макрос, но это не так. Это условно поддерживаемый предопределенный идентификатор, поэтому вы не можете проверить его с помощью #if defined
или #ifdef
.
Если компиляторы не могут сказать вам, поддерживается ли это (они могли бы через _FUNC_SUPPORTED
или что-то в этом роде, я не говорю, что они действительно это делают), вам нужно будет проверить компилятор вместо фактический идентификатор.
Что-то по строкам:
#ifndef __FUNCTION_NAME__
#ifdef WIN32 //WINDOWS
#define __FUNCTION_NAME__ __FUNCTION__
#else //*NIX
#define __FUNCTION_NAME__ __func__
#endif
#endif
Ответ 2
они не являются макросами препроцессора, такими как __FILE__ and __LINE__
, или переменные.
Взято по следующей ссылке:
http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Names.html
Кроме того, проверьте этот другой вопрос, на который был дан ответ, похожий на ваш:
Как проверить, можно ли использовать __PRETTY_FUNCTION__?
Пример:
#ifdef _MSC_VER // Visual Studio
#define FUNCTION_NAME __FUNCTION__
#endif
Ответ 3
Как часто Boost - это кросс-платформенное решение с BOOST_CURRENT_FUNCTION
, определенном в <boost/current_function.hpp>
.
Ответ 4
Я хотел бы добавить, что макрос __FUNCTION__
определен как для GCC, так и для MSVC. Хотя он нестандартен, он доступен для обоих компиляторов.
Стандартные предопределенные макросы GCC:
C99 вводит __func__
, и GCC предоставил __FUNCTION__
в течение длительного времени. Обе эти строки содержат имя текущей функции (есть небольшие семантические различия, см. Руководство GCC). Ни один из них не является макросом; препроцессор не знает имя текущей функции. Они, как правило, полезны вместе с __FILE__
и __LINE__
.
Предопределенные макросы MSV:
__FUNCTION__
Действителен только в функции. Определяет неразделенное имя закрывающей функции как строковый литерал.
__FUNCTION__
не расширяется, если вы используете параметр компилятора /EP или/P.
См. __FUNCDNAME__
для примера.
Таким образом, использование __FUNCTION__
будет в порядке, поскольку оба компилятора реализуют его. Хотя вы не можете получать одинаковые результаты для обоих компиляторов, но это может быть приемлемым в некоторых ситуациях.