Apa perbedaan antara __PRETTY_FUNCTION__, __FUNCTION__, __func__?


221

Apa perbedaan antara __PRETTY_FUNCTION__, __FUNCTION__, __func__, dan di mana mereka didokumentasikan? Bagaimana cara saya memutuskan mana yang akan digunakan?

Jawaban:


266

__func__adalah pengidentifikasi yang dinyatakan secara implisit yang memperluas ke variabel array karakter yang berisi nama fungsi ketika digunakan di dalam suatu fungsi. Itu ditambahkan ke C di C99. Dari C99 §6.4.2.2 / 1:

Pengidentifikasi __func__secara implisit dinyatakan oleh penerjemah seolah-olah, segera setelah tanda kurung pembukaan masing-masing definisi fungsi, deklarasi

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

muncul, di mana fungsi-nama adalah nama dari fungsi leksikal-melampirkan. Nama ini adalah nama fungsi tanpa hiasan.

Perhatikan bahwa ini bukan makro dan tidak memiliki arti khusus selama preprocessing.

__func__ditambahkan ke C ++ di C ++ 11, di mana ia ditentukan sebagai mengandung "string yang didefinisikan dengan implementasi" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), yang tidak cukup seperti berguna sebagai spesifikasi dalam C. (Proposal asli untuk ditambahkan __func__ke C ++ adalah N1642 ).

__FUNCTION__adalah ekstensi pra-standar yang didukung oleh beberapa kompiler C (termasuk gcc dan Visual C ++); secara umum, Anda harus menggunakan __func__mana yang didukung dan hanya digunakan __FUNCTION__jika Anda menggunakan kompiler yang tidak mendukungnya (misalnya, Visual C ++, yang tidak mendukung C99 dan belum mendukung semua C ++ 0x, tidak menyediakan__func__ ).

__PRETTY_FUNCTION__adalah ekstensi gcc yang sebagian besar sama dengan __FUNCTION__, kecuali bahwa untuk fungsi C ++ berisi "cantik" nama fungsi termasuk tanda tangan dari fungsi. Visual C ++ memiliki ekstensi yang serupa (tetapi tidak cukup identik) __FUNCSIG__,.

Untuk makro yang tidak standar, Anda perlu membaca dokumentasi kompiler Anda. Ekstensi Visual C ++ termasuk dalam dokumentasi MSDN dari kompiler C ++ "Predefined Macro" . Ekstensi dokumentasi gcc dijelaskan di halaman dokumentasi gcc "Function Names as Strings."


Bisakah Anda menautkan ke spesifikasi C99 (ada tautan mengambang di sumber Anda), seperti apa jawaban yang menang?
Matt Joiner

1
@ legends2k: Tidak, ini adalah "string yang ditentukan implementasi" di C ++ 11. Itu bahasa sebenarnya dari spesifikasi. Lihat §8.4.1 [dcl.fct.def.general] / 8.
James McNellis

2
Perhatikan bahwa walaupun gcc dan VC menyediakan __FUNCTION__, keduanya melakukan hal yang sedikit berbeda. gcc memberikan yang setara dengan __func__. VC memberikan versi nama yang belum didekorasi, tetapi masih menghiasi,. Untuk metode bernama "foo", gcc akan memberi Anda "foo", VC akan memberi "my_namespace::my_class::foo".
Adrian McCarthy

1
Yang aneh adalah bahwa saya menggunakan MSVC 2017 CE dan ketika saya mengetiknya __PRETTY_FUNCTION__muncul di daftar sebagai tersedia dan ketika saya menggerakkan mouse saya di atasnya, itu memang menampilkan informasi tentang nama fungsi, namun gagal untuk dikompilasi.
Francis Cugler

1
@ Franciscugler Saya terkejut dengan ini juga! Lihat pertanyaan saya di atasnya stackoverflow.com/questions/48857887/…
Adam Badura

108

Meskipun tidak sepenuhnya menjawab pertanyaan awal, ini mungkin yang ingin dilihat kebanyakan orang Google.

Untuk 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
Saya tahu ini bukan jawaban yang tepat, tetapi mungkin itulah yang ingin dilihat oleh hampir semua orang yang ingin melihat ini :) (jika mereka malas mencoba sendiri)
Petr

5
Panggilan yang adil, ini bagus untuk dilihat.
Matt Joiner

13
Output yang sama dari dentang 3.5
Doncho Gunchev

Oke, tetapi apakah itu __func__berfungsi saat tertanam di fungsi lain? Katakanlah saya punya function1, tidak perlu argumen. function1 memanggil function2 yang mencakup __func__, nama fungsi mana yang akan dicetak, 1 atau 2?
MarcusJ

@MarcusJ mengapa tidak mencobanya sendiri ... __func__ini adalah makro, ia akan menerjemahkan ke fungsi apa pun yang sedang Anda masuki. Jika Anda memasukkannya ke f1 dan memanggil f1 di f2, Anda akan selalu mendapatkan f1.
Petr

41

__PRETTY_FUNCTION__ menangani fitur C ++: kelas, ruang nama, templat, dan kelebihan

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

Kompilasi dan jalankan:

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

Keluaran:

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

Anda mungkin juga tertarik dengan jejak tumpukan dengan nama fungsi: cetak panggilan tumpukan di C atau C ++

Diuji di 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 masuk ke C ++ 20, jadi kami masih memiliki cara lain untuk melakukannya.

Dokumentasi mengatakan:

constexpr const char * function_name () const noexcept;

6 Pengembalian: Jika objek ini mewakili posisi di tubuh fungsi, mengembalikan NTBS yang ditentukan implementasi yang harus sesuai dengan nama fungsi. Jika tidak, kembalikan string kosong.

di mana NTBS berarti "Null Terminated Byte String".

Saya akan mencobanya ketika dukungan datang ke GCC, GCC 9.1.0 dengan g++-9 -std=c++2amasih tidak mendukungnya.

https://en.cppreference.com/w/cpp/utility/source_location klaim penggunaan akan seperti:

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

Output yang mungkin:

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

jadi perhatikan bagaimana ini mengembalikan informasi penelepon, dan karena itu sempurna untuk penggunaan dalam pencatatan, lihat juga: Apakah ada cara untuk mendapatkan nama fungsi di dalam fungsi C ++?


13

__func__didokumentasikan dalam standar C ++ 0x pada bagian 8.4.1. Dalam kasus ini, ini adalah variabel fungsi lokal yang telah ditentukan dari formulir:

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

di mana "nama fungsi" adalah specfic implementasi. Ini berarti bahwa setiap kali Anda mendeklarasikan suatu fungsi, kompiler akan menambahkan variabel ini secara implisit ke fungsi Anda. Hal yang sama berlaku untuk __FUNCTION__dan __PRETTY_FUNCTION__. Meskipun huruf besar mereka, mereka bukan makro. Meskipun __func__merupakan tambahan untuk C ++ 0x

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

masih akan mengkompilasi kode menggunakan __func__.

__PRETTY_FUNCTION__dan __FUNCTION__didokumentasikan di sini http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__hanyalah nama lain untuk __func__. __PRETTY_FUNCTION__sama seperti __func__di C tetapi di C ++ itu berisi tipe tanda tangan juga.


__func__bukan bagian dari C ++ 03. Itu telah ditambahkan dalam C ++ 0x, tetapi C ++ 0x belum "standar C ++," masih dalam bentuk konsep.
James McNellis

2
@JamesMcNellis Sekarang, jadi jelas komentarnya, untuk menghilangkan kebisingan
daramarak

7

Bagi mereka, yang bertanya-tanya bagaimana hasilnya dalam VS.

Pembaruan 1 MSVC 2015, cl.exe versi 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>();
}

keluaran:

dari main ():
utama
utama
int __cdecl main (void)

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

Menggunakan __PRETTY_FUNCTION__pemicu kesalahan pengidentifikasi yang tidak diumumkan, seperti yang diharapkan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.