__PRETTY_FUNCTION__, __FUNCTION__, __func__ arasındaki fark nedir?


Yanıtlar:


266

__func__, bir işlev içinde kullanıldığında işlev adını içeren bir karakter dizisi değişkenine genişleyen dolaylı olarak bildirilen bir tanımlayıcıdır. C99'da C'ye ilave edildi. Gönderen C99 / 1 §6.4.2.2:

Tanımlayıcı __func__, çevirmen tarafından her bir işlev tanımının açılış ayrağını hemen takip eden sanki beyanı dolaylı olarak bildirir.

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

burada işlev-adı sözcüksel olarak çevreleyen işlevin adıdır. Bu ad, işlevin süslenmemiş adıdır.

Bir makro olmadığını ve ön işleme sırasında özel bir anlamı olmadığını unutmayın.

__func__C ++ 11'de C ++ 'a eklenmiştir, burada "bir uygulama tanımlı dize" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8) içerdiği belirtilmiştir. ( __func__C ++ ' a eklenecek orijinal öneri N1642 idi ).

__FUNCTION__bazı C derleyicilerinin desteklediği standart öncesi bir uzantıdır (gcc ve Visual C ++ dahil); genel olarak, __func__desteklendiği yerde kullanmalı ve yalnızca onu desteklemeyen __FUNCTION__bir derleyici kullanıyorsanız kullanmalısınız (örneğin, C99'u desteklemeyen ve henüz tüm C ++ 0x'i desteklemeyen Visual C ++, sağlamak __func__).

__PRETTY_FUNCTION____FUNCTION__C ++ işlevleri için işlevin imzası da dahil olmak üzere işlevin "güzel" adını içermesi dışında çoğunlukla aynı olan bir gcc uzantısıdır . Visual C ++ benzer (ama tam olarak aynı değil) bir uzantıya sahiptir __FUNCSIG__.

Standart olmayan makrolar için derleyicinizin belgelerine başvurmak isteyeceksiniz. Visual C ++ uzantıları, C ++ derleyicisinin "Önceden Tanımlı Makrolar" MSDN belgelerinde bulunur . Gcc dokümantasyon uzantıları gcc dokümantasyon sayfası "Dizeler Olarak İşlev Adları" bölümünde açıklanmaktadır .


Kazanan cevap gibi görünen şey için C99 belirtimine (kaynağınızda yüzen bir bağlantı var) bağlantı verebilir misiniz?
Matt Joiner

1
@ legends2k: Hayır, C ++ 11'de "uygulama tanımlı bir dize". Spesifikasyondaki gerçek dil budur. Bkz. §8.4.1 [dcl.fct.def.general] / 8.
James McNellis

2
Hem gcc hem de VC sağlarken __FUNCTION__, biraz farklı şeyler yaptığını unutmayın. gcc eşdeğerini verir __func__. VC, adın dekore edilmemiş, ancak hala süslenmiş versiyonunu verir. "Foo" adlı bir yöntem için, gcc size "foo", VC'yi verecektir "my_namespace::my_class::foo".
Adrian McCarthy

1
Merak ettiğim şey, MSVC 2017 CE kullanıyorum ve yazdığımda __PRETTY_FUNCTION__listede mevcut olarak görünüyor ve faremi üzerine getirdiğimde, işlev adı hakkında bilgi görüntülüyor, ancak derlenemiyor.
Francis Cugler

1
@FrancisCugler Buna da şaşırdım!
Sorumla

108

Orijinal soruyu tam olarak cevaplamamasına rağmen, muhtemelen bu googling yapan çoğu insanın görmek istediği şey budur.

GCC için:

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
Bunun doğru bir cevap olmadığını biliyorum, ama muhtemelen bu google neredeyse herkes görmek istedim :) (kendilerini denemek için tembel ise)
Petr

5
Adil çağrı, bunu görmek güzel.
Matt Joiner

13
Clang

Tamam, ama __func__başka bir fonksiyona gömüldüğünde çalışıyor mu? Diyelim ki function1 var, argüman almıyor. function1 __func__, hangi fonksiyon adı yazdırılacaktır, 1 veya 2'yi içeren fonksiyon2'yi çağırır ?
MarcusJ

@MarcusJ neden kendiniz denemiyorsunuz ... __func__bir makro, şu anda hangi işlevde olursanız olun. F1'e koyar ve f2'de f1'i çağırırsanız , her zaman f1 elde edersiniz.
Petr

41

__PRETTY_FUNCTION__ C ++ özelliklerini işler: sınıflar, ad alanları, şablonlar ve aşırı yük

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

Derleyin ve çalıştırın:

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

Çıktı:

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

Ayrıca, işlev adlarına sahip yığın izleri de ilginizi çekebilir: C veya C ++ ile çağrı yığını yazdırma

Ubuntu 19.04, GCC 8.3.0'da test edilmiştir.

C ++ 20 std::source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf C ++ 20'ye girdi, bu yüzden bunu yapmanın başka bir yolu daha var.

Belgeler diyor ki:

constexpr const char * işlev_adı () const noexcept;

6 Döndürür: Bu nesne bir işlev gövdesindeki bir konumu temsil ediyorsa, işlev adına karşılık gelmesi gereken, uygulama tanımlı bir NTBS döndürür. Aksi takdirde, boş bir dize döndürür.

burada NTBS "Boş Sonlandırılmış Bayt Dizesi" anlamına gelir.

Destek GCC'ye geldiğinde bir deneyeceğim, GCC 9.1.0 g++-9 -std=c++2ahala desteklemiyor.

https://en.cppreference.com/w/cpp/utility/source_location talep kullanımı şöyle olacaktır:

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

Olası çıktı:

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

bu arayanın bilgilerini nasıl döndürdüğünü ve bu nedenle günlüğe kaydetmede kullanım için mükemmel olduğunu unutmayın, ayrıca bkz: C ++ işlevinin içinde işlev adı almanın bir yolu var mı?


13

__func__bölüm 8.4.1'de C ++ 0x standardında belgelenmiştir. Bu durumda, formun önceden tanımlanmış bir işlev yerel değişkeni:

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

burada "işlev adı" uygulama özelliğidir. Bu, bir işlev bildirdiğinizde, derleyicinin bu değişkeni işlevinize örtük olarak ekleyeceği anlamına gelir. Aynısı __FUNCTION__ve için de geçerlidir __PRETTY_FUNCTION__. Üst yayınlarına rağmen makro değiller. Her ne __func__kadar C ++ 0x ekidir

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

ile kod yine de derlenir __func__.

__PRETTY_FUNCTION__ve __FUNCTION__burada http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names belgelenmiştir . __FUNCTION__sadece başka bir isim __func__. C ile __PRETTY_FUNCTION__aynıdır __func__ancak C ++ 'da da tip imzasını içerir.


__func__C ++ 03'ün bir parçası değildir. C ++ 0x'de eklendi, ancak C ++ 0x henüz "C ++ standardı" değil, hala taslak formda.
James McNellis

2
@JamesMcNellis Gürültüyü kaldırmak için şimdi, yorumları çok net
daramarak

7

VS'ye nasıl gittiğini merak edenler için.

MSVC 2015 Güncelleştirme 1, cl.exe sürümü 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>();
}

çıktı:

main () işlevinden:
ana
ana
int __cdecl main (geçersiz)

A :: f () 'den:
Bir :: f <int, yüzer>
f
void __cdecl A <int, kayan nokta> :: f <bool> (void)

Kullanılması __PRETTY_FUNCTION__beklendiği gibi tetikleyiciler, tanımlayıcının hatayı bildirilmeyen.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.