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


Respuestas:


266

__func__es un identificador declarado implícitamente que se expande a una variable de matriz de caracteres que contiene el nombre de la función cuando se usa dentro de una función. Fue agregado a C en C99. De C99 §6.4.2.2 / 1:

El __func__traductor declara implícitamente el identificador como si, inmediatamente después de la llave de apertura de cada definición de función, la declaración

static const char __func__[] = "function-name";

aparecido, donde nombre-función es el nombre de la función de cierre léxico. Este nombre es el nombre sin adornos de la función.

Tenga en cuenta que no es una macro y no tiene un significado especial durante el preprocesamiento.

__func__ se agregó a C ++ en C ++ 11, donde se especifica que contiene "una cadena definida por la implementación" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), que no es tan útil como la especificación en C. (La propuesta original para agregar __func__ a C ++ fue N1642 ).

__FUNCTION__es una extensión preestándar que admiten algunos compiladores de C (incluidos gcc y Visual C ++); en general, deberías usar__func__ donde sea compatible y solo usar __FUNCTION__si está utilizando un compilador que no lo admite (por ejemplo, Visual C ++, que no admite C99 y aún no admite todo C ++ 0x, no proporcionar __func__).

__PRETTY_FUNCTION__ es una extensión de gcc que es casi igual a __FUNCTION__ , excepto que para las funciones de C ++ contiene el nombre "bonito" de la función, incluida la firma de la función. Visual C ++ tiene una extensión similar (pero no del todo idénticos), __FUNCSIG__.

Para las macros no estándar, deberá consultar la documentación de su compilador. Las extensiones de Visual C ++ se incluyen en la documentación de MSDN de las "Macros predefinidas" del compilador de C ++ . Las extensiones de documentación de gcc se describen en la página de documentación de gcc "Nombres de funciones como cadenas".


¿Se puede vincular a la especificación C99 (hay un enlace flotante en su fuente), para lo que parece la respuesta ganadora?
Matt Joiner

1
@ legends2k: No, es "una cadena definida por la implementación" en C ++ 11. Ese es el lenguaje real de la especificación. Ver §8.4.1 [dcl.fct.def.general] / 8.
James McNellis

2
Tenga en cuenta que si bien tanto gcc como VC proporcionan __FUNCTION__, hacen cosas ligeramente diferentes. gcc da el equivalente de __func__. VC da la versión sin decorar, pero aún adornada, del nombre. Para un método llamado "foo", gcc te dará "foo", VC te dará "my_namespace::my_class::foo".
Adrian McCarthy

1
Lo curioso es que estoy usando MSVC 2017 CE y cuando lo escribo __PRETTY_FUNCTION__aparece en la lista como disponible y cuando muevo el mouse sobre él, muestra información sobre el nombre de la función, sin embargo, no se compila.
Francis Cugler

1
@FrancisCugler ¡También me sorprendió esto! Vea mi pregunta en ella stackoverflow.com/questions/48857887/…
Adam Badura

108

A pesar de no responder completamente la pregunta original, esto es probablemente lo que la mayoría de las personas que buscaban en Google quería ver.

Para GCC:

petanb@debian:~$ cat test.cpp 
#include <iostream>

int main(int argc, char **argv)
{
    std::cout << __func__ << std::endl
              << __FUNCTION__ << std::endl
              << __PRETTY_FUNCTION__ << std::endl;
}
petanb@debian:~$ g++ test.cpp 
petanb@debian:~$ 
petanb@debian:~$ ./a.out 
main
main
int main(int, char**)

66
Sé que esta no es una respuesta adecuada, pero probablemente sea lo que casi todos los que googlearon esto querían ver :) (si son flojos para probarse a sí mismos)
Petr

55
Llamada justa, esto es agradable de ver.
Matt Joiner

13
Misma salida de clang 3.5
Doncho Gunchev

Ok, pero ¿ __func__funciona cuando está incrustado en otra función? Digamos que tengo function1, no requiere argumentos. function1 llama a function2 que incluye __func__, ¿qué nombre de función se imprimirá, 1 o 2?
MarcusJ

@ MarcusJ, ¿por qué no probarlo usted mismo? __func__Es una macro, se traducirá a cualquier función en la que se encuentre actualmente. Si lo coloca en f1 y llama a f1 en f2, siempre obtendrá f1.
Petr

41

__PRETTY_FUNCTION__ maneja características de C ++: clases, espacios de nombres, plantillas y sobrecarga

main.cpp

#include <iostream>

namespace N {
    class C {
        public:
            template <class T>
            static void f(int i) {
                (void)i;
                std::cout << __func__ << std::endl
                          << __FUNCTION__ << std::endl
                          << __PRETTY_FUNCTION__ << std::endl;
            }
            template <class T>
            static void f(double f) {
                (void)f;
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
}

int main() {
    N::C::f<char>(1);
    N::C::f<void>(1.0);
}

Compilar y ejecutar:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

Salida:

f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]

También puede estar interesado en los seguimientos de pila con nombres de funciones: imprimir la pila de llamadas en C o C ++

Probado en Ubuntu 19.04, GCC 8.3.0.

C ++ 20 std::source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf entró en C ++ 20, por lo que tenemos otra forma de hacerlo.

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++2atodaví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!

así que tenga en cuenta cómo esto devuelve la información de la persona que llama y, por lo tanto, es perfecto para su uso en el registro, vea también: ¿Hay alguna manera de obtener el nombre de la función dentro de una función de C ++?


13

__func__está documentado en el estándar C ++ 0x en la sección 8.4.1. En este caso es una variable local de función predefinida de la forma:

static const char __func__[] = "function-name ";

donde "nombre de función" es específico de implementación. Esto significa que siempre que declare una función, el compilador agregará esta variable implícitamente a su función. Lo mismo es cierto de __FUNCTION__y __PRETTY_FUNCTION__. A pesar de sus mayúsculas, no son macros. Aunque __func__es una adición a C ++ 0x

g++ -std=c++98 ....

seguirá compilando código usando __func__ .

__PRETTY_FUNCTION__y __FUNCTION__están documentados aquí http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__es solo otro nombre para __func__. __PRETTY_FUNCTION__es lo mismo que __func__en C pero en C ++ también contiene la firma de tipo.


__func__no es parte de C ++ 03. Se ha agregado en C ++ 0x, pero C ++ 0x aún no es "el estándar de C ++", todavía está en forma de borrador.
James McNellis

2
@JamesMcNellis Es ahora, así que aclaren los comentarios, eliminar el ruido
daramarak

7

Para aquellos que se preguntan cómo va en VS.

MSVC 2015 Update 1, cl.exe versión 19.00.24215.1:

#include <iostream>

template<typename X, typename Y>
struct A
{
  template<typename Z>
  static void f()
  {
    std::cout << "from A::f():" << std::endl
      << __FUNCTION__ << std::endl
      << __func__ << std::endl
      << __FUNCSIG__ << std::endl;
  }
};

void main()
{
  std::cout << "from main():" << std::endl
    << __FUNCTION__ << std::endl
    << __func__ << std::endl
    << __FUNCSIG__ << std::endl << std::endl;

  A<int, float>::f<bool>();
}

salida:

de main ():
principal
principal
int __cdecl main (nulo)

de A :: f ():
A <int, float> :: f
F
void __cdecl A <int, float> :: f <bool> (void)

El uso de __PRETTY_FUNCTION__disparadores de error de identificador no declarado, como se esperaba.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.