Apa perbedaan antara __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, dan di mana mereka didokumentasikan? Bagaimana cara saya memutuskan mana yang akan digunakan?
Apa perbedaan antara __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, dan di mana mereka didokumentasikan? Bagaimana cara saya memutuskan mana yang akan digunakan?
Jawaban:
__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, deklarasistatic 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."
__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"
.
__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.
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**)
__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?
__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.
__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++2a
masih 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 ++?
__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.
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.