Qual é a diferença entre __PRETTY_FUNCTION__, __FUNCTION__, __func__?

221

Qual é a diferença entre __PRETTY_FUNCTION__, __FUNCTION__, __func__, e onde eles estão documentadas? Como decido qual deles usar?

Matt Joiner
fonte

Respostas:

266

__func__é um identificador declarado implicitamente que se expande para uma variável de matriz de caracteres que contém o nome da função quando é usada dentro de uma função. Foi adicionado a C em C99. Do ponto C99 §6.4.2.2 / 1:

O identificador __func__é declarado implicitamente pelo tradutor como se, imediatamente após a chave de abertura de cada definição de função, a declaração

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

apareceu, onde nome da função é o nome da função que encerra lexicamente. Este nome é o nome sem adornos da função.

Observe que não é uma macro e não tem significado especial durante o pré-processamento.

__func__foi adicionado ao C ++ no C ++ 11, onde é especificado como contendo "uma string definida pela implementação" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), que não é tão útil como a especificação em C. (A proposta original para adicionar __func__ao C ++ era N1642 ).

__FUNCTION__é uma extensão pré-padrão que alguns compiladores C suportam (incluindo gcc e Visual C ++); em geral, você deve usar __func__onde é suportado e usar somente __FUNCTION__se estiver usando um compilador que não o suporte (por exemplo, Visual C ++, que não oferece suporte ao C99 e ainda não suporta todo o C ++ 0x, não fornecer __func__).

__PRETTY_FUNCTION__é uma extensão do gcc que é basicamente a mesma __FUNCTION__, exceto que para as funções do C ++, ela contém o nome "bonito" da função, incluindo a assinatura da função. Visual C ++ tem uma extensão semelhante (mas não completamente idêntica) __FUNCSIG__,.

Para macros fora do padrão, convém consultar a documentação do seu compilador. As extensões do Visual C ++ estão incluídas na documentação do MSDN das "Macros predefinidas" do compilador C ++ . As extensões da documentação do gcc são descritas na página de documentação do gcc "Nomes de funções como seqüências de caracteres".

James McNellis
fonte
Você pode criar um link para a especificação C99 (há um link flutuante na sua fonte), para o que parece ser a resposta vencedora?
Matt Joiner
1
@ legends2k: Não, é "uma sequência definida pela implementação" no C ++ 11. Essa é a linguagem real da especificação. Veja §8.4.1 [dcl.fct.def.general] / 8.
22613 James McNellis
2
Observe que, embora o gcc e o VC forneçam __FUNCTION__, eles fazem coisas ligeiramente diferentes. gcc fornece o equivalente a __func__. O VC fornece a versão não decorada, mas ainda adornada, do nome. Para um método chamado "foo", o gcc fornecerá a você "foo", o VC fornecerá "my_namespace::my_class::foo".
Adrian McCarthy
1
O curioso é que estou usando o MSVC 2017 CE e, quando digito, __PRETTY_FUNCTION__ele aparece na lista como disponível e quando movo o mouse sobre ele, ele exibe informações sobre o nome da função, mas falha na compilação.
22878 Francis Cugler
1
@FrancisCugler Fiquei surpreso com isso também! Veja minha pergunta nele stackoverflow.com/questions/48857887/…
Adam Badura 28/02
108

Apesar de não responder totalmente à pergunta original, é provavelmente o que a maioria das pessoas pesquisando no Google queria ver.

Para o 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**)
Petr
fonte
6
Eu sei que isto não é uma resposta adequada, mas é provavelmente o que quase todo mundo que Google Esta queria ver :) (se eles são preguiçosos para tentar-se)
Petr
5
É justo ver isso.
Matt Joiner
13
A mesma saída do clang 3.5
Doncho Gunchev
Ok, mas __func__funciona quando incorporado em outra função? Digamos que eu tenho function1, não é necessário argumentos. function1 chama function2 que inclui __func__, qual nome da função será impresso, 1 ou 2?
MarcusJ
@ MarcusJ por que não tentar você mesmo ... a __func__macro é traduzida para qualquer função em que você esteja atualmente. Se você colocar em f1 e chamar f1 em f2, você sempre obterá f1.
Petr
41

__PRETTY_FUNCTION__ lida com recursos do C ++: classes, namespaces, modelos e 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);
}

Compile e execute:

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

Resultado:

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

Você também pode estar interessado em rastreamentos de pilha com nomes de função: imprimir pilha de chamada em C ou C ++

Testado no 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 entrou no C ++ 20, portanto, temos mais uma maneira de fazê-lo.

A documentação diz:

constexpr const char * nome_da_função () const noexcept;

6 Retorna: se este objeto representa uma posição no corpo de uma função, retorna um NTBS definido pela implementação que deve corresponder ao nome da função. Caso contrário, retorna uma string vazia.

onde NTBS significa "Cadeia de bytes nulos terminados".

Vou tentar quando o suporte chegar ao GCC, o GCC 9.1.0 com g++-9 -std=c++2aainda não o suporta.

https://en.cppreference.com/w/cpp/utility/source_location afirma que o uso 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!");
}

Saída possível:

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

observe como isso retorna as informações do chamador e, portanto, é perfeito para uso em log, consulte também: Existe uma maneira de obter o nome da função dentro de uma função C ++?

Ciro Santilli adicionou uma nova foto
fonte
13

__func__está documentado no padrão C ++ 0x na seção 8.4.1. Nesse caso, é uma variável local de função predefinida do formulário:

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

onde "nome da função" é uma implementação específica. Isso significa que sempre que você declarar uma função, o compilador adicionará essa variável implicitamente à sua função. O mesmo vale para __FUNCTION__e __PRETTY_FUNCTION__. Apesar de serem maiúsculas, não são macros. Embora __func__seja uma adição ao C ++ 0x

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

ainda irá compilar o código usando __func__.

__PRETTY_FUNCTION__e __FUNCTION__estão documentados aqui http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__é apenas outro nome para __func__. __PRETTY_FUNCTION__é o mesmo que __func__em C, mas em C ++ também contém a assinatura de tipo.

sashang
fonte
__func__não faz parte do C ++ 03. Ele foi adicionado no C ++ 0x, mas o C ++ 0x ainda não é "o padrão C ++", ainda está em forma de rascunho.
James McNellis
2
@JamesMcNellis É agora, para limpar os comentários, para remover o ruído
daramarak
7

Para aqueles que se perguntam como isso acontece no VS.

MSVC 2015, atualização 1, cl.exe versão 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>();
}

resultado:

from main ():
a Principal
a Principal
int __cdecl principal (vazio)

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

O uso de __PRETTY_FUNCTION__disparadores de erro de identificador não declarado, conforme o esperado.

finnan
fonte