Uso de __FILE__, __LINE__ y __FUNCTION__ en C ++

158

Suponiendo que su compilador de C ++ los admite, ¿hay alguna razón particular para no usarlos?__FILE__ , __LINE__y __FUNCTION__para fines de registro y depuración?

Me preocupa principalmente dar al usuario datos engañosos, por ejemplo, informar el número de línea incorrecto o la función como resultado de la optimización, o tomar un impacto en el rendimiento como resultado.

Básicamente, puedo confiar __FILE__, __LINE__y __FUNCTION__para siempre hacer lo correcto?

Runcible
fuente
LINE debería hacer lo correcto. Lo he usado y sus cohortes ampliamente, incluido PRETTY_FUNCTION . ... Pero ... bueno, ahora mismo estoy mirando el código donde se encuentra LINE . Probablemente porque está en un bloque catch para el manejo de excepciones try / catch.
Krazy Glew
44
relevante: referencia de gcc para macros predefinidas
Alexander Malakhov

Respuestas:

191

__FUNCTION__no es estándar, __func__existe en C99 / C ++ 11. Los otros ( __LINE__y __FILE__) están bien.

Siempre informará el archivo y la línea correctos (y funcionará si elige usar __FUNCTION__/ __func__). La optimización no es un factor ya que es una expansión de macro en tiempo de compilación; será no afectar al rendimiento de ninguna manera.

Evan Teran
fuente
3
__func__es un problema en C ++. C99 no dice una palabra sobre los argumentos predeterminados, etc., casos en los que no es tan obvio cómo __func__debería comportarse en C ++.
wilhelmtell
44
@thr: mientras haces un buen punto. Estaba bastante claro que __func__existe en c99, no en c ++. De todos modos, creo que una implementación razonable de __func__en c ++ solo daría como resultado el nombre destrozado. Como no soy un escritor compilador, en realidad no es mi decisión.
Evan Teran
¿Qué compiladores no admiten __FUNCTION__en absoluto? ¿Qué compiladores, excepto gcc reciente, tratan esto como una variable, no como una macro?
cuenca
36
__func__ahora está en el estándar C ++ 11.
VX
38

En casos raros, puede ser útil cambiar la línea dada por __LINE__otra cosa. He visto que GNU configure hace eso para algunas pruebas para informar los números de línea apropiados después de insertar un vudú entre líneas que no aparecen en los archivos fuente originales. Por ejemplo:

#line 100

Hará que las siguientes líneas comiencen con __LINE__100. Opcionalmente, puede agregar un nuevo nombre de archivo

#line 100 "file.c"

Raramente es útil. Pero si es necesario, no hay alternativas que conozca. En realidad, en lugar de la línea, también se puede usar una macro que debe dar como resultado cualquiera de las dos formas anteriores. Usando la biblioteca de preprocesador boost, puede incrementar la línea actual en 50:

#line BOOST_PP_ADD(__LINE__, 50)

Pensé que es útil mencionarlo ya que preguntaste sobre el uso de __LINE__y__FILE__ . Nunca se obtienen suficientes sorpresas de C ++ :)

Editar: @Jonathan Leffler proporciona algunos casos de uso más buenos en los comentarios:

Jugar con #line es muy útil para los preprocesadores que desean mantener los errores informados en el código C del usuario en línea con el archivo fuente del usuario. Yacc, Lex y (más en casa para mí) los preprocesadores ESQL / C hacen eso.

Johannes Schaub - litb
fuente
29

FYI: g ++ ofrece la macro no estándar __PRETTY_FUNCTION__. Hasta ahora no sabía sobre C99 __func__ (¡gracias Evan!). Creo que todavía prefiero __PRETTY_FUNCTION__ cuando está disponible para el alcance adicional de la clase.

PD:

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
fuente
2
Es bueno saber acerca de la __PRETTY_FUNCTION__. ¡Muy útil!
Zheng Qu
8

Personalmente, soy reacio a usarlos para cualquier cosa que no sea depurar mensajes. Lo he hecho, pero trato de no mostrar ese tipo de información a los clientes o usuarios finales. Mis clientes no son ingenieros y, a veces, no son expertos en informática. Podría registrar esta información en la consola, pero, como dije, de mala gana, excepto para las versiones de depuración o para las herramientas internas. Sin embargo, supongo que depende de la base de clientes que tenga.

Craig S
fuente
29
"Podría registrar esta información en la consola", o mejor aún: registrarlo en un archivo para que si algo sale mal, puede pedirle al cliente que se lo envíe ...
Christoph
7

C ++ 20 std::source_location

C ++ finalmente ha agregado una opción no macro, y probablemente dominará en algún momento en el futuro cuando C ++ 20 se generalice:

La documentación dice:

constexpr const char * nombre_función () const noexcept;

6 Devuelve: Si este objeto representa una posición en el cuerpo de una función, devuelve un NTBS definido por la implementación que debería corresponder al nombre de la función. De lo contrario, devuelve una cadena vacía.

donde NTBS significa "Cadena de bytes terminada nula".

Lo intentaré cuando llegue el soporte a GCC, GCC 9.1.0 con g++-9 -std=c++2a todavía no lo admite.

https://en.cppreference.com/w/cpp/utility/source_location el uso de reclamos será como:

#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!");
}

Salida posible:

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

__PRETTY_FUNCTION__vs __FUNCTION__vs __func__vsstd::source_location::function_name

Respondido a: ¿Cuál es la diferencia entre __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Hay <experimental/source_location>en gcc-9 actual.
陈浩南
5

Los utilizo todo el tiempo. Lo único que me preocupa es regalar IP en los archivos de registro. Si los nombres de sus funciones son realmente buenos, podría estar haciendo que un secreto comercial sea más fácil de descubrir. Es algo así como enviar con símbolos de depuración, solo que es más difícil encontrar cosas. En el 99.999% de los casos no saldrá nada malo.

JeffCharter
fuente
1
Buen punto para mencionar. Es trivial extraer esta información utilizando la stringsutilidad para extraer todos los datos en forma de cadena del ejecutable. Incluso los ejecutables comprimidos se pueden extraer. Sea muy consciente de lo que envía al sitio de un cliente. Muchas veces, los competidores pueden obtener sus ejecutables, aunque no se supone que lo hagan.
Marty
Es posible con constexpr que usa una tabla de búsqueda o XOR a nivel de bit, etc. para ofuscar cualquier cadena literal en su binario. Hay varios ejemplos por ahí si busca. Por supuesto, la ofuscación es solo ofuscación y no seguridad, pero si no desea que sus archivos y funciones sean obvios en el binario, es una opción.
idij hace