Sự khác biệt giữa những gì __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, và nơi được họ ghi nhận? Làm thế nào để tôi quyết định sử dụng cái nào?
Sự khác biệt giữa những gì __PRETTY_FUNCTION__
, __FUNCTION__
, __func__
, và nơi được họ ghi nhận? Làm thế nào để tôi quyết định sử dụng cái nào?
Câu trả lời:
__func__
là một định danh được khai báo ngầm mở rộng thành một biến mảng ký tự chứa tên hàm khi nó được sử dụng bên trong hàm. Nó đã được thêm vào C trong C99. Từ C99 §6.4.2.2 / 1:
Mã định danh
__func__
được người dịch khai báo ngầm như thể, ngay sau dấu ngoặc mở của mỗi định nghĩa hàm, khai báostatic const char __func__[] = "function-name";
đã xuất hiện, trong đó tên hàm là tên của hàm bao quanh từ vựng. Tên này là tên chưa được bổ sung của hàm.
Lưu ý rằng nó không phải là macro và nó không có ý nghĩa đặc biệt trong quá trình tiền xử lý.
__func__
đã được thêm vào C ++ trong C ++ 11, trong đó nó được chỉ định là có chứa "chuỗi định nghĩa triển khai" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8), không hoàn toàn như hữu ích như đặc tả trong C. (Đề xuất ban đầu để thêm __func__
vào C ++ là N1642 ).
__FUNCTION__
là một phần mở rộng tiền chuẩn mà một số trình biên dịch C hỗ trợ (bao gồm gcc và Visual C ++); nói chung, bạn nên sử dụng __func__
nơi nó được hỗ trợ và chỉ sử dụng __FUNCTION__
nếu bạn đang sử dụng trình biên dịch không hỗ trợ nó (ví dụ: Visual C ++, không hỗ trợ C99 và chưa hỗ trợ tất cả C ++ 0x, không hỗ trợ cung cấp __func__
).
__PRETTY_FUNCTION__
là một phần mở rộng gcc gần giống như __FUNCTION__
, ngoại trừ các hàm C ++, nó chứa tên "khá" của hàm bao gồm cả chữ ký của hàm. Visual C ++ có phần mở rộng tương tự (nhưng không hoàn toàn giống nhau) __FUNCSIG__
.
Đối với các macro không chuẩn, bạn sẽ muốn tham khảo tài liệu của nhà biên dịch. Các phần mở rộng Visual C ++ được bao gồm trong tài liệu MSDN của " Trình biên dịch được xác định trước" của trình biên dịch C ++ . Các phần mở rộng tài liệu gcc được mô tả trong trang tài liệu gcc "Tên hàm dưới dạng chuỗi".
__FUNCTION__
, chúng làm những việc hơi khác nhau. gcc cho tương đương với __func__
. VC đưa ra phiên bản của tên chưa được trang trí nhưng vẫn được tô điểm. Đối với một phương thức có tên là "foo", gcc sẽ cung cấp cho bạn "foo"
, VC sẽ cung cấp cho bạn "my_namespace::my_class::foo"
.
__PRETTY_FUNCTION__
nó sẽ hiển thị trong danh sách là có sẵn và khi tôi di chuyển chuột qua nó, nó sẽ hiển thị thông tin về tên hàm, tuy nhiên nó không biên dịch được.
Mặc dù không trả lời đầy đủ câu hỏi ban đầu, nhưng đây có lẽ là điều mà hầu hết mọi người đang googling này muốn xem.
Đối với 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__
hoạt động khi nó được nhúng trong một chức năng khác? Hãy nói rằng tôi có hàm1, nó không có đối số. function1 gọi function2 bao gồm __func__
, tên hàm nào sẽ được in, 1 hoặc 2?
__func__
là một macro, nó sẽ dịch sang bất kỳ chức năng nào bạn đang làm. Nếu bạn đặt nó vào F1 và gọi F1 trong f2, bạn sẽ luôn nhận được F1.
__PRETTY_FUNCTION__
xử lý các tính năng C ++: lớp, không gian tên, mẫu và quá tải
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);
}
Biên dịch và chạy:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Đầu ra:
f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]
Bạn cũng có thể quan tâm đến dấu vết ngăn xếp với tên hàm: in ngăn xếp cuộc gọi trong C hoặc C ++
Đã thử nghiệm trong Ubuntu 19.04, GCC 8.3.0.
C ++ 20 std::source_location::function_name
http://www.open-std.org/jtc1/sc22/wg21/docs/ con / 2019 / p1208r5.pdf đã đi vào C ++ 20, vì vậy chúng tôi có một cách khác để làm điều đó.
Các tài liệu nói:
constexpr const char * function_name () const noexcept;
6 Trả về: Nếu đối tượng này đại diện cho một vị trí trong phần thân của hàm, trả về một NTBS được xác định thực hiện tương ứng với tên hàm. Nếu không, trả về một chuỗi rỗng.
Trong đó NTBS có nghĩa là "Chuỗi Byte Null chấm dứt".
Tôi sẽ dùng thử khi hỗ trợ đến GCC, GCC 9.1.0 mà g++-9 -std=c++2a
vẫn không hỗ trợ.
https://en.cppreference.com/w/cpp/utility/source_location yêu cầu sử dụng sẽ như sau:
#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!");
}
Sản lượng có thể:
info:main.cpp:16:main Hello world!
vì vậy hãy lưu ý cách điều này trả về thông tin người gọi và do đó hoàn hảo cho việc sử dụng trong ghi nhật ký, xem thêm: Có cách nào để lấy tên hàm bên trong hàm C ++ không?
__func__
được ghi lại trong tiêu chuẩn C ++ 0x tại mục 8.4.1. Trong trường hợp này, đó là một biến cục bộ của hàm được xác định trước của biểu mẫu:
static const char __func__[] = "function-name ";
trong đó "tên hàm" là specfic thực hiện. Điều này có nghĩa là bất cứ khi nào bạn khai báo một hàm, trình biên dịch sẽ thêm biến này vào hàm của bạn. Điều tương tự cũng đúng __FUNCTION__
và __PRETTY_FUNCTION__
. Mặc dù có họ, họ không phải là macro. Mặc dù __func__
là một bổ sung cho C ++ 0x
g++ -std=c++98 ....
vẫn sẽ biên dịch mã bằng cách sử dụng __func__
.
__PRETTY_FUNCTION__
và __FUNCTION__
được ghi lại ở đây http://gcc.gnu.org/onlinesocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names . __FUNCTION__
chỉ là một tên khác cho __func__
. __PRETTY_FUNCTION__
giống như __func__
trong C nhưng trong C ++, nó cũng chứa chữ ký loại.
__func__
không phải là một phần của C ++ 03. Nó đã được thêm vào trong C ++ 0x, nhưng C ++ 0x vẫn chưa phải là "tiêu chuẩn C ++", nó vẫn ở dạng bản nháp.
Đối với những người, những người tự hỏi làm thế nào nó đi trong VS.
MSVC 2015 Cập nhật 1, phiên bản 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>();
}
đầu ra:
từ chính (): chủ yếu chủ yếu int __cdecl chính (void) từ A :: f (): Một <int, float> :: f f void __cdecl A <int, float> :: f <bool> (void)
Sử dụng các __PRETTY_FUNCTION__
kích hoạt lỗi định danh không khai báo, như mong đợi.