Qual è la differenza tra __PRETTY_FUNCTION__, __FUNCTION__, __func__?


Risposte:


266

__func__è un identificatore implicitamente dichiarato che si espande in una variabile di array di caratteri contenente il nome della funzione quando viene utilizzato all'interno di una funzione. Fu aggiunto a C nel C99. Da C99 §6.4.2.2 / 1:

L'identificatore __func__viene implicitamente dichiarato dal traduttore come se, immediatamente dopo il controvento iniziale di ciascuna definizione di funzione, la dichiarazione

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

è apparso, dove nome-funzione è il nome della funzione che racchiude il lessico. Questo nome è il nome disadorno della funzione.

Si noti che non è una macro e non ha alcun significato speciale durante la preelaborazione.

__func__è stato aggiunto a C ++ in C ++ 11, dove è specificato che contiene "una stringa definita dall'implementazione" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), che non è del tutto utile come specifica in C. (La proposta originale da aggiungere __func__al C ++ era N1642 ).

__FUNCTION__è un'estensione pre-standard supportata da alcuni compilatori C (inclusi gcc e Visual C ++); in generale, è necessario utilizzare __func__dove è supportato e utilizzare solo __FUNCTION__se si utilizza un compilatore che non lo supporta (ad esempio Visual C ++, che non supporta C99 e non supporta ancora tutto C ++ 0x, non fornire __func__).

__PRETTY_FUNCTION__è un'estensione gcc che è per lo più la stessa __FUNCTION__, ad eccezione del fatto che per le funzioni C ++ contiene il nome "grazioso" della funzione inclusa la firma della funzione. Visual C ++ ha un'estensione simile (ma non del tutto identiche) __FUNCSIG__.

Per le macro non standard, ti consigliamo di consultare la documentazione del compilatore. Le estensioni di Visual C ++ sono incluse nella documentazione MSDN delle "Macro predefinite" del compilatore C ++ . Le estensioni della documentazione di gcc sono descritte nella pagina della documentazione di gcc "Nomi di funzioni come stringhe".


Puoi collegarti alla specifica C99 (c'è un collegamento mobile nella tua fonte), per quello che sembra la risposta vincente?
Matt Joiner,

1
@ legends2k: No, è "una stringa definita dall'implementazione" in C ++ 11. Questo è il linguaggio reale dalle specifiche. Vedi §8.4.1 [dcl.fct.def.general] / 8.
James McNellis,

2
Si noti che mentre entrambi forniscono CCG e VC __FUNCTION__, fanno cose leggermente diverse. gcc fornisce l'equivalente di __func__. VC fornisce la versione non decorata, ma ancora ornata, del nome. Per un metodo chiamato "pippo", gcc ti darà "foo", VC ti darà "my_namespace::my_class::foo".
Adrian McCarthy,

1
Ciò che è curioso è che sto usando MSVC 2017 CE e quando __PRETTY_FUNCTION__lo scrivo appare nell'elenco come disponibile e quando ci muovo sopra con il mouse, visualizza informazioni sul nome della funzione, ma non riesce a compilare.
Francis Cugler,

1
@FrancisCugler Sono stato sorpreso anche da questo! Vedi la mia domanda su stackoverflow.com/questions/48857887/…
Adam Badura,

108

Nonostante non abbia risposto completamente alla domanda originale, questo è probabilmente ciò che la maggior parte delle persone che cercavano su Google voleva vedere.

Per 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**)

6
So che questa non è una risposta corretta, ma è probabilmente ciò che quasi tutti coloro che hanno cercato su Google hanno voluto vedere :) (se sono pigri per provare se stessi)
Petr

5
Buona chiamata, è bello da vedere.
Matt Joiner,

13
Stessa produzione di clang 3.5
Doncho Gunchev,

Ok, ma __func__funziona quando è incorporato in un'altra funzione? Diciamo che ho function1, non ci vuole argomento. function1 chiama function2 che include __func__, quale nome di funzione verrà stampato, 1 o 2?
MarcusJ,

@MarcusJ perché non provarlo tu stesso ... __func__è una macro, si tradurrà in qualunque funzione tu sia attualmente. Se lo metti in f1 e chiami f1 in f2, otterrai sempre f1.
Petr,

41

__PRETTY_FUNCTION__ gestisce le funzionalità C ++: classi, spazi dei nomi, modelli e sovraccarico

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);
}

Compila ed esegui:

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

Produzione:

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

Potresti anche essere interessato a tracce di stack con nomi di funzioni: stampa stack di chiamate in C o C ++

Testato in 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 è entrato in C ++ 20, quindi abbiamo ancora un altro modo per farlo.

La documentazione dice:

constexpr const char * nome_funzione () const noexcept;

6 Restituisce: se questo oggetto rappresenta una posizione nel corpo di una funzione, restituisce un NTBS definito dall'implementazione che dovrebbe corrispondere al nome della funzione. Altrimenti, restituisce una stringa vuota.

dove NTBS significa "Null Terminated Byte String".

Lo proverò quando il supporto arriva a GCC, GCC 9.1.0 con g++-9 -std=c++2aancora non lo supporta.

https://en.cppreference.com/w/cpp/utility/source_location l' utilizzo delle attestazioni sarà simile a:

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

Uscita possibile:

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

quindi nota come questo restituisce le informazioni sul chiamante, ed è quindi perfetto per l'uso nella registrazione, vedi anche: C'è un modo per ottenere il nome della funzione all'interno di una funzione C ++?


13

__func__è documentato nello standard C ++ 0x nella sezione 8.4.1. In questo caso è una variabile locale della funzione predefinita del modulo:

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

dove "nome funzione" è specifico dell'implementazione. Ciò significa che ogni volta che dichiari una funzione, il compilatore aggiungerà implicitamente questa variabile alla tua funzione. Lo stesso vale per __FUNCTION__e __PRETTY_FUNCTION__. Nonostante il loro carattere maiuscolo, non sono macro. Anche se __func__è un'aggiunta a C ++ 0x

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

compilerà comunque il codice usando __func__.

__PRETTY_FUNCTION__e __FUNCTION__sono documentati qui http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__è solo un altro nome per __func__. __PRETTY_FUNCTION__è lo stesso __func__di C ma in C ++ contiene anche la firma del tipo.


__func__non fa parte di C ++ 03. È stato aggiunto in C ++ 0x, ma C ++ 0x non è ancora "lo standard C ++", è ancora in forma bozza.
James McNellis l'

2
@JamesMcNellis Adesso è, così chiaro i commenti, per rimuovere il rumore
daramarak,

7

Per quelli che si chiedono come va in VS.

Aggiornamento 1 di MSVC 2015, versione cl.exe 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>();
}

produzione:

da main ():
principale
principale
int __cdecl main (vuoto)

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

L'uso di __PRETTY_FUNCTION__attiva un errore di identificazione non dichiarato, come previsto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.