Подтвердить что ты не робот

Предопределенные макросы для имени функции __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__?
4b9b3361

Ответ 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__ будет в порядке, поскольку оба компилятора реализуют его. Хотя вы не можете получать одинаковые результаты для обоих компиляторов, но это может быть приемлемым в некоторых ситуациях.