2009-03-24 14 views
33

Después de años de usar la gran macro fea MFC ASSERT, finalmente he decidido deshacerme de ella y crear la macro ASSERT final.¿Cómo encontrar el nombre de la función actual en tiempo de ejecución?

Estoy bien con obtener el número de archivo y línea, e incluso la expresión que falló. Puedo mostrar un cuadro de mensaje con estos botones, y Abortar/Reintentar/Cancelar.

Y cuando presiono Reintentar, el depurador VS salta a la línea que contiene la llamada ASSERT (a diferencia del desensamblaje en algún lugar como algunas otras funciones ASSERT). Entonces todo está funcionando.

Pero lo que sería genial sería mostrar el nombre de la función que falló.

Luego puedo decidir si debo depurarlo sin tratar de adivinar de qué función proviene el nombre del archivo.

p. Ej. si tengo la siguiente función:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
    ASSERT(lpCreateStruct->cx > 0); 
    ... 
} 

Luego, cuando los incendios ASSERT, el cuadro de mensaje mostrarían algo como:

Function = CMainFrame::OnCreate 

Así que, ¿cuál es la forma más sencilla de conocer el nombre de la función actual, por lo tiempo de ejecución?

No debería usar MFC ni el .NET framework, aunque sí uso ambos.
Debe ser lo más portátil posible.

+0

Si tiene acceso a las [aplicaciones de depuración de John Robbins para Microsoft® .NET y Microsoft Windows®] (http://www.amazon.com/Debugging-Applications-Microsoft®-Microsoft-Pro-Developer/dp/0735615365/ref = sr_1_16/175-5814253-7853112? Ie = UTF8 & s = electronics & qid = 1237928779 & sr = 8-16) definitivamente debe ver las aserciones de la biblioteca BugSlayerUtil en el CD suministrado. Son específicos de Windows, pero realmente definitivos. – Paul

+0

Eché un vistazo a http://www.koders.com/cpp/fid3653A5E08C30DB8B7551729FBED0BC3D51B19AD8.aspx pero no parecía mostrar el nombre de la función. Por lo tanto, creo que mi versión es más definitiva que la suya: D – demoncodemonkey

+0

Muestra stacktrace. Stacktrace contiene nombres de funciones, ¿no es así? – Paul

Respuesta

48

La macro puede contener la macro __FUNCTION__. No se equivoque, el nombre de la función será insertada en el código expandido en tiempo de compilación, pero será el nombre de función correcto para cada llamada a su macro. Por lo tanto, "parece que" sucede en tiempo de ejecución;)

p.

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__ 

int foo() 
{ 
    int a = 0; 
    THROW_IF(a > 0); // will throw "error in foo()" 
} 
+4

Desafortunadamente, '__FUNCTION__' no es estándar. '__func__' * es * estándar, pero no es un literal de cadena; actúa como una variable, por lo que no se puede concatenar fácilmente. – ephemient

+0

a la derecha. pero, afortunadamente, el OP está utilizando MFC, por lo que la multiplataforma probablemente no sea un problema. –

+2

Lo mencioné porque OP pidió portabilidad. – ephemient

18

El ++ preprocesador C macro __FUNCTION__ da el nombre de la función.

Tenga en cuenta que si utiliza esto, no es realmente obteniendo el nombre de archivo, número de línea o nombre de función en tiempo de ejecución. Las macros se expanden por el preprocesador, y compilados en.

El __FUNCTION__ macro, como __LINE__ y __FILE__, es parte del estándar de la lengua, y es portátil.

programa Ejemplo:

#include <iostream> 
#using namespace std; 

void function1() 
{ 
     cout << "my function name is: " << __FUNCTION__ << "\n"; 
} 
int main() 
{ 
     cout << "my function name is: " << __FUNCTION__ << "\n"; 
     function1(); 
     return 0; 
} 

de salida:

 
my function name is: main 
my function name is: function1 
+0

__FUNCTION__ no es parte del estándar de lenguaje C++ (no he rechazado tu voto por esto, pero supongo que alguien más lo hizo) –

+0

buen punto, creo que he leído mal algo. de acuerdo con http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html, __func__ es parte del estándar C99 (aunque no necesariamente todo lo admite). __FUNCTION__ no lo es, aunque si los grandes cumplidores (MSDN/GCC) lo admiten, es efectivamente portátil. – YenTheFirst

+1

Tenga en cuenta que __func__ tampoco es parte de C++. –

4

Puede utilizar el __FUNCTION__ macro el cual en tiempo de compilación se ampliará al nombre de la función.

Aquí hay un ejemplo de cómo usarlo en una macro assert.

#define ASSERT(cond) \ 
    do { if (!(cond)) \ 
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\ 
    } while(0) 

void MessageBoxFunction(const char* const msg, ...) 
{ 
    char szAssertMsg[2048]; 

    // format args 
    va_list vargs; 
    va_start(vargs, msg); 
    vsprintf(szAssertMsg, msg, vargs); 
    va_end(vargs); 

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK); 
} 
+0

Argh en el "..." pero por lo demás una buena respuesta, gracias. – demoncodemonkey

+0

¿por qué tienes que odiar en el '...'? Es un código válido –

+0

@demoncodemonkey: Trevor hace una gran pregunta. ¿Por qué Andrew no debería usar una función variada aquí? – unforgettableid

18

No hay una solución estándar. Sin embargo, BOOST_CURRENT_FUNCTION es portátil para todos los propósitos prácticos. El encabezado no depende de ninguno de los otros encabezados de Boost, por lo que se puede usar de forma independiente si la carga general de toda la biblioteca es inaceptable.

+1

Gracias, no uso Boost (todavía) pero al menos sé que hay un sustituto para __FUNCTION__ si alguna vez tengo la necesidad de portarlo. – demoncodemonkey

+0

El encabezado de {{BOOST_CURRENT_FUNCTION}} es independiente. Puede descargarlo y ponerlo en su base de código sin nada más de Boost. –

7

En GCC puede usar la macro __PRETTY_FUNCTION__.
Microsoft también tiene una macro equivalente __func__ aunque no tengo esa disponible para probar.

p. Ej. utilizar __PRETTY_FUNCTION__ poner algo como esto en el comienzo de sus funciones y obtendrá una traza completa

void foo(char* bar){ 
    cout << __PRETTY_FUNCTION__ << std::endl 
} 

cual la salida

void foo(char* bar) 

También tienen las macros __FILE__ y __LINE__ disponibles bajo toda norma compiladores c/C++ si desea generar aún más información.

En la práctica, tengo una clase de depuración especial que utilizo en lugar de cout. Al definir las variables de entorno apropiadas, puedo obtener un seguimiento completo del programa. Podrías hacer algo similar. Estas macros son increíblemente útiles y es realmente genial poder activar una depuración selectiva como esta en el campo.

EDITAR: aparentemente __func__ es parte de la norma? no lo sabía Desafortunadamente, solo da el nombre de la función y no los parámetros también. Me gusta el __PRETTY_FUNC__ de gcc, pero no es portátil para otros compiladores.

GCC también admite __FUNCTION__.

Cuestiones relacionadas