Jaka jest różnica między funkcją, funkcją, func?

Jaka jest różnica między __PRETTY_FUNCTION__, __FUNCTION__, __func__, a gdzie są udokumentowane? Jak zdecydować, którego z nich użyć?

Author: Matt Joiner, 2010-12-08

5 answers

__func__ jest niejawnie zadeklarowanym identyfikatorem, który rozszerza się do zmiennej tablicy znaków zawierającej Nazwę funkcji, gdy jest używana wewnątrz funkcji. Został dodany do C w C99. Od C99 §6.4.2.2/1:

Identyfikator __func__ jest niejawnie deklarowany przez tłumacza, tak jakby bezpośrednio po nawiasie otwierającym każdej definicji funkcji deklaracja

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

Pojawił się, gdzie function-name jest nazwą funkcji leksykalnie zamykającej. To nazwa jest nienadorowaną nazwą funkcji.

Zauważ, że nie jest to makro i nie ma specjalnego znaczenia podczas wstępnego przetwarzania.

__func__ został dodany do C++ w C++11, gdzie jest określony jako zawierający "łańcuch zdefiniowany w implementacji"(C++11 §8.4.1 [dcl.fct.def.ogólna] / 8), która nie jest tak przydatna jak specyfikacja w C. (pierwotna propozycja dodania __func__ do C++ to N1642 ).

__FUNCTION__ jest pre-standardowym rozszerzeniem, które niektóre kompilatory C obsługują (w tym GCC i Visual C++); ogólnie rzecz biorąc, powinieneś używać __func__ Gdzie jest on obsługiwany i używać __FUNCTION__ tylko jeśli używasz kompilatora, który go nie obsługuje (na przykład Visual C++, który nie obsługuje C99 i nie obsługuje jeszcze wszystkich C++0x, nie dostarcza __func__).

__PRETTY_FUNCTION__ jest rozszerzeniem gcc, które jest w większości takie samo jak __FUNCTION__, z tym wyjątkiem, że dla funkcji C++ zawiera "ładną" nazwę funkcji łącznie z podpisem funkcji. Visual C++ ma podobny (ale nie całkiem identyczne) rozszerzenie, __FUNCSIG__.

W przypadku niestandardowych makr, należy zapoznać się z dokumentacją kompilatora. Rozszerzenia Visual C++ są zawarte w dokumentacji MSDN kompilatora "predefiniowanych makr". Rozszerzenia dokumentacji gcc są opisane na stronie dokumentacji gcc " nazwy funkcji jako ciągi znaków."

 287
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Pomimo Nie pełnej odpowiedzi na pierwotne pytanie, to jest prawdopodobnie to, co większość ludzi googlujących to chciał zobaczyć.

Dla GCC:

$ cat test.cpp 
#include <iostream>

int main(int argc, char **argv)
{
    std::cout << __func__ << std::endl
              << __FUNCTION__ << std::endl
              << __PRETTY_FUNCTION__ << std::endl;
}
$ g++ test.cpp 
$ ./a.out 
main
main
int main(int, char**)
 126
Author: Petr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-10 07:07:58

__PRETTY_FUNCTION__ obsługuje funkcje C++: klasy, przestrzenie nazw, szablony i przeciążenia

Main.cpp

#include <iostream>

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

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

Skompiluj i uruchom:

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

Wyjście:

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

Możesz być również zainteresowany śladami stosu z nazwami funkcji: Drukuj stos wywołań w C lub C++

Testowane w 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 poszedł do C++20, więc mamy jeszcze inny sposób.

Dokumentacja mówi:

Constexpr const char * function_name () const noexcept;

6 zwraca: jeśli obiekt ten reprezentuje pozycję w ciele funkcji, zwraca zdefiniowane w implementacji NTB, które powinny odpowiadać nazwa funkcji. W przeciwnym razie zwraca pusty łańcuch.

Gdzie NTBS oznacza "null zakończony Łańcuch bajtowy".

Spróbuję kiedy wsparcie dotrze do GCC, GCC 9.1.0 z g++-9 -std=c++2a nadal nie wesprzyj to.

Https://en.cppreference.com/w/cpp/utility/source_location claims usage will be like:

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

Możliwe wyjście:

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

Więc zauważ, jak to zwraca informacje o wywołującym i dlatego jest idealne do użycia w logowaniu, Zobacz także: czy istnieje sposób, aby uzyskać nazwę funkcji wewnątrz funkcji C++?

 52
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-14 14:55:36

__func__ jest udokumentowany w standardzie C++0x w sekcji 8.4.1. W tym przypadku jest to predefiniowana zmienna lokalna funkcji o postaci:

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

Gdzie" nazwa funkcji " jest implementacją specfic. Oznacza to, że za każdym razem, gdy deklarujesz funkcję, kompilator doda tę zmienną niejawnie do twojej funkcji. To samo dotyczy __FUNCTION__ i __PRETTY_FUNCTION__. Pomimo wielkich liter, nie są to makra. Chociaż {[2] } jest dodatkiem do C++0x

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

Będzie nadal kompilować kod używając __func__.

__PRETTY_FUNCTION__ i __FUNCTION__ są udokumentowane tutaj http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names. __FUNCTION__ to tylko inna nazwa __func__. __PRETTY_FUNCTION__ jest tym samym co __func__ W C, ale w C++ zawiera również sygnaturę typu.

 16
Author: sashang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-08 09:14:55

Dla tych, którzy zastanawiają się, jak to idzie w VS.

MSVC 2015 Update 1, cl.wersja 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>();
}

Wyjście:

from main():
main
main
int __cdecl main(void)

from A::f():
A<int,float>::f
f
void __cdecl A<int,float>::f&ltbool>(void)

Użycie __PRETTY_FUNCTION__ powoduje, zgodnie z oczekiwaniami, nierejestrowany błąd identyfikatora.

 9
Author: finnan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 15:21:37