อะไรคือความแตกต่างระหว่าง__PRETTY_FUNCTION__
, __FUNCTION__
, __func__
และสถานที่ที่พวกเขาจะได้รับการบันทึก? ฉันจะตัดสินใจได้อย่างไรว่าควรใช้อันไหน
อะไรคือความแตกต่างระหว่าง__PRETTY_FUNCTION__
, __FUNCTION__
, __func__
และสถานที่ที่พวกเขาจะได้รับการบันทึก? ฉันจะตัดสินใจได้อย่างไรว่าควรใช้อันไหน
คำตอบ:
__func__
เป็นตัวบ่งชี้ที่ประกาศโดยปริยายซึ่งขยายเป็นตัวแปรอาร์เรย์อักขระที่มีชื่อฟังก์ชันเมื่อใช้ภายในฟังก์ชัน มันถูกเพิ่มไปยัง C ใน C99 จากC99 §6.4.2.2 / 1:
ตัวบ่งชี้
__func__
ถูกประกาศโดยผู้แปลโดยนัยราวกับว่าทันทีหลังจากวงเล็บเปิดของคำจำกัดความของฟังก์ชันแต่ละรายการการประกาศstatic const char __func__[] = "function-name";
ปรากฏขึ้นโดยที่ function-name คือชื่อของฟังก์ชั่นการปิดล้อมด้วยคำศัพท์ ชื่อนี้เป็นชื่อที่ไม่มีการตกแต่งของฟังก์ชัน
โปรดทราบว่ามันไม่ใช่แมโครและไม่มีความหมายพิเศษในระหว่างการประมวลผลล่วงหน้า
__func__
ถูกเพิ่มใน C ++ ใน C ++ 11 โดยที่มันถูกระบุว่ามี "สตริงการนำไปปฏิบัติ" (C ++ 11 §8.4.1 [dcl.fct.def.general] / 8) ซึ่งไม่ค่อยเป็น มีประโยชน์ตามข้อกำหนดใน C (ข้อเสนอดั้งเดิมที่จะเพิ่ม__func__
ใน C ++ คือN1642 )
__FUNCTION__
เป็นส่วนขยายมาตรฐานล่วงหน้าที่คอมไพเลอร์ C บางตัวสนับสนุน (รวมถึง gcc และ Visual C ++) โดยทั่วไปคุณควรใช้__func__
ตำแหน่งที่รองรับและใช้เฉพาะ__FUNCTION__
เมื่อคุณใช้คอมไพเลอร์ที่ไม่รองรับ (ตัวอย่างเช่น Visual C ++ ซึ่งไม่รองรับ C99 และยังไม่รองรับ C ++ 0x ทั้งหมด แต่ไม่รองรับ ให้__func__
)
__PRETTY_FUNCTION__
เป็นส่วนขยาย gcc ที่ส่วนใหญ่เหมือนกับ__FUNCTION__
ยกเว้นสำหรับฟังก์ชั่น C ++ มันมีชื่อ "สวย" ของฟังก์ชั่นรวมถึงลายเซ็นของฟังก์ชั่น Visual C ++ มีคล้ายกัน ( แต่ไม่เหมือนกันมาก) __FUNCSIG__
ส่วนขยาย
สำหรับมาโครที่ไม่ได้มาตรฐานคุณจะต้องศึกษาเอกสารประกอบของคอมไพเลอร์ของคุณ c ++ Visual ส่วนขยายจะรวมอยู่ในเอกสาร MSDN ของ C ++ คอมไพเลอร์ของ"ที่กำหนดไว้ล่วงหน้าแมโคร" นามสกุลเอกสาร gcc อธิบายไว้ในหน้าเอกสารคู่มือ gcc "ชื่อฟังก์ชั่นเป็นสตริง"
__FUNCTION__
แต่พวกเขาทำสิ่งที่แตกต่างกันเล็กน้อย GCC __func__
ให้เทียบเท่า VC ให้ชื่อรุ่นที่ยังไม่ได้ตกแต่ง แต่ยังคงประดับอยู่ สำหรับวิธีการที่ชื่อ "foo" GCC จะทำให้คุณ"foo"
, VC "my_namespace::my_class::foo"
จะให้
__PRETTY_FUNCTION__
มันจะปรากฏในรายการว่าพร้อมใช้งานและเมื่อฉันเลื่อนเมาส์ไปที่มันจะแสดงข้อมูลเกี่ยวกับชื่อฟังก์ชั่นอย่างไรก็ตามมันไม่สามารถรวบรวมได้
แม้จะไม่ได้ตอบคำถามเดิมอย่างเต็มที่ แต่นี่อาจเป็นสิ่งที่คนส่วนใหญ่ที่ Google อยากเห็น
สำหรับ 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__
ใช้ได้เมื่อฝังอยู่ในฟังก์ชันอื่นหรือไม่ ให้บอกว่าฉันมี function1 มันไม่มีข้อโต้แย้ง function1 เรียกใช้ function2 ที่รวม__func__
ชื่อฟังก์ชันใดที่จะพิมพ์ 1 หรือ 2
__func__
มันเป็นมาโครมันจะแปลไปยังฟังก์ชั่นที่คุณใช้อยู่ถ้าคุณใส่มันลงใน f1 และเรียก f1 ใน f2 คุณจะได้ f1 เสมอ
__PRETTY_FUNCTION__
จัดการคุณสมบัติ C ++: คลาสเนมสเปซเทมเพลตและโอเวอร์โหลด
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);
}
รวบรวมและเรียกใช้:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
เอาท์พุท:
f
f
static void N::C::f(int) [with T = char]
static void N::C::f(double) [with T = void]
คุณอาจสนใจในการติดตามสแต็กที่มีชื่อฟังก์ชัน: call call stack ใน C หรือ C ++
ทดสอบใน 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ไปที่ C ++ 20 ดังนั้นเราจึงมีวิธีอื่นในการทำเช่นนั้น
เอกสารบอกว่า:
constexpr const ถ่าน * function_name () const noexcept;
6 คืน: ถ้าวัตถุนี้แสดงถึงตำแหน่งในเนื้อความของฟังก์ชันส่งคืน NTBS ที่กำหนดใช้งานที่ควรสอดคล้องกับชื่อฟังก์ชัน มิฉะนั้นส่งคืนสตริงว่าง
โดยที่ NTBS หมายถึง "Null Terminated Byte String"
ฉันจะลองดูเมื่อการสนับสนุนมาถึง GCC GCC 9.1.0 โดยที่g++-9 -std=c++2a
ยังไม่รองรับ
https://en.cppreference.com/w/cpp/utility/source_locationการใช้สิทธิ์จะเป็นดังนี้:
#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!");
}
เอาต์พุตที่เป็นไปได้:
info:main.cpp:16:main Hello world!
ดังนั้นโปรดทราบว่าวิธีนี้ส่งกลับข้อมูลผู้โทรและดังนั้นจึงสมบูรณ์แบบสำหรับการใช้งานในการบันทึกดูเพิ่มเติม: มีวิธีรับชื่อฟังก์ชั่นภายในฟังก์ชั่น C ++ หรือไม่?
__func__
มีการบันทึกไว้ในมาตรฐาน C ++ 0x ที่ส่วน 8.4.1 ในกรณีนี้มันเป็นตัวแปรโลคอลของฟังก์ชั่นที่กำหนดไว้ล่วงหน้าของแบบฟอร์ม:
static const char __func__[] = "function-name ";
โดยที่ "ชื่อฟังก์ชั่น" เป็นการใช้งานที่เฉพาะเจาะจง ซึ่งหมายความว่าเมื่อใดก็ตามที่คุณประกาศฟังก์ชันคอมไพเลอร์จะเพิ่มตัวแปรนี้ให้กับฟังก์ชันของคุณโดยปริยาย เช่นเดียวกับที่เป็นจริงของและ__FUNCTION__
__PRETTY_FUNCTION__
แม้จะเป็นตัวพิมพ์ใหญ่ แต่ก็ไม่ใช่มาโคร แม้ว่าจะ__func__
เป็นส่วนเสริมของ C ++ 0x
g++ -std=c++98 ....
__func__
จะยังคงรวบรวมรหัสใช้
__PRETTY_FUNCTION__
และ__FUNCTION__
มีเอกสารที่นี่http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names เป็นเพียงชื่ออีก__FUNCTION__
เหมือนกับใน C แต่ใน C ++ จะมีลายเซ็นประเภทเช่นกัน__func__
__PRETTY_FUNCTION__
__func__
__func__
ไม่ได้เป็นส่วนหนึ่งของ C ++ 03 มันได้รับการเพิ่มใน C ++ 0x แต่ C ++ 0x ยังไม่ได้ "มาตรฐาน C ++" มันยังคงอยู่ในรูปแบบร่าง
สำหรับผู้ที่สงสัยว่ามันจะไปใน VS
อัปเดต MSVC 2015 1 รุ่น 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>();
}
เอาท์พุท:
จาก main (): หลัก หลัก int __cdecl main (เป็นโมฆะ) จาก A :: f (): <int, float> :: ฉ ฉ โมฆะ __cdecl A <int, float> :: f <bool> (void)
การใช้__PRETTY_FUNCTION__
ทริกเกอร์ระบุข้อผิดพลาดที่ไม่ได้ประกาศตามที่คาดไว้