__FILE__, __LINE__ และ __FUNCTION__ การใช้งานใน C ++


158

ทะนงว่าคุณ c ++ คอมไพเลอร์สนับสนุนพวกเขาจะมีเหตุผลใด ๆ โดยเฉพาะอย่างยิ่งไม่ได้กับการใช้งาน__FILE__, __LINE__และ__FUNCTION__สำหรับการบันทึกและวัตถุประสงค์ในการแก้จุดบกพร่อง?

ฉันมักเกี่ยวข้องกับการให้ข้อมูลที่ทำให้ผู้ใช้เข้าใจผิดเช่นการรายงานหมายเลขบรรทัดหรือฟังก์ชั่นที่ไม่ถูกต้องอันเป็นผลมาจากการปรับให้เหมาะสม

โดยทั่วไปฉันสามารถไว้วางใจ__FILE__, __LINE__และ__FUNCTION__จะเสมอทำสิ่งที่ถูกต้อง?


LINEควรทำสิ่งที่ถูกต้อง ฉันได้ใช้มันและสมุนของมันอย่างกว้างขวางรวมทั้งPRETTY_FUNCTION ... แต่ ... เอ่อฉันเพิ่งจะดูรหัสที่LINEอยู่ อาจเป็นเพราะอยู่ใน catch catch สำหรับลอง / catch catch handling handling
Krazy Glew

คำตอบ:


191

__FUNCTION__ไม่ใช่มาตรฐาน__func__มีอยู่ใน C99 / C ++ 11 ส่วนอื่น ๆ ( __LINE__และ__FILE__) ก็ใช้ได้

มันจะรายงานไฟล์และบรรทัดที่ถูกต้องเสมอ (และฟังก์ชั่นหากคุณเลือกที่จะใช้__FUNCTION__/ __func__) การเพิ่มประสิทธิภาพเป็นปัจจัยที่ไม่ใช่เพราะมันเป็นเวลาขยายตัวแมโครรวบรวม; มันจะไม่ส่งผลต่อประสิทธิภาพ แต่อย่างใด


3
__func__เป็นปัญหาใน C ++ C99 ไม่ได้พูดอะไรเกี่ยวกับการมีปากเสียงเริ่มต้นเป็นต้นกรณีที่มันไม่ชัดเจนว่า__func__ควรประพฤติอย่างไรใน C ++
wilhelmtell

4
@thr: ในขณะที่คุณทำให้เป็นจุดที่ดี ฉันค่อนข้างชัดเจนว่า__func__มีอยู่ใน c99 ไม่ใช่ c ++ โดยไม่คำนึงถึงฉันคิดว่าการใช้งานที่เหมาะสม__func__ใน c ++ จะส่งผลให้มีชื่อที่ยุ่งเหยิง เนื่องจากฉันไม่ใช่นักเขียนคอมไพเลอร์จึงไม่ใช่การโทรของฉัน
Evan Teran

คอมไพเลอร์ใดที่ไม่สนับสนุน__FUNCTION__เลย? คอมไพเลอร์ใดยกเว้น gcc ที่ผ่านมาให้ถือว่าเป็นตัวแปรไม่ใช่มาโคร
อ่าง

36
__func__ขณะนี้อยู่ในมาตรฐาน C ++ 11
VX

38

ในบางกรณีมันอาจมีประโยชน์ในการเปลี่ยนบรรทัดที่มอบให้__LINE__กับสิ่งอื่น ฉันเคยเห็น GNU ตั้งค่าคอนฟิกว่าสำหรับการทดสอบบางอย่างเพื่อรายงานหมายเลขบรรทัดที่เหมาะสมหลังจากที่มันแทรก voodoo ระหว่างบรรทัดที่ไม่ปรากฏในไฟล์ต้นฉบับ ตัวอย่างเช่น:

#line 100

จะทำให้บรรทัดต่อไปนี้เริ่มต้นด้วย__LINE__100 คุณสามารถเลือกเพิ่มชื่อไฟล์ใหม่ได้

#line 100 "file.c"

มันไม่ค่อยมีประโยชน์เท่าไหร่ แต่ถ้าจำเป็นก็ไม่มีทางเลือกอื่นที่ฉันรู้ ที่จริงแล้วแทนที่จะเป็นบรรทัดก็สามารถใช้มาโครได้เช่นกันซึ่งจะต้องส่งผลให้ฟอร์มสองแบบใดข้างต้น การใช้ไลบรารีตัวประมวลผลก่อนเพิ่มคุณสามารถเพิ่มบรรทัดปัจจุบันได้ 50:

#line BOOST_PP_ADD(__LINE__, 50)

ผมคิดว่ามันมีประโยชน์ที่จะพูดถึงมันตั้งแต่คุณถามเกี่ยวกับการใช้งานของและ__LINE__ __FILE__ไม่มีใครประหลาดใจพอจาก C ++ :)

แก้ไข: @Jonathan Leffler จัดเตรียมกรณีการใช้งานที่ดีขึ้นในความคิดเห็น:

การ Messing กับ #line มีประโยชน์อย่างมากสำหรับตัวประมวลผลล่วงหน้าที่ต้องการเก็บรายงานข้อผิดพลาดในรหัส C ของผู้ใช้ให้สอดคล้องกับไฟล์ต้นฉบับของผู้ใช้ Yacc, Lex และ (มากกว่าอยู่ที่บ้านกับฉัน) ตัวประมวลผลล่วงหน้า ESQL / C ทำเช่นนั้น


29

FYI: g ++ นำเสนอมาโคร __PRETTY_FUNCTION__ ที่ไม่ได้มาตรฐาน จนถึงตอนนี้ฉันไม่รู้เกี่ยวกับ C99 __func__ (ขอบคุณ Evan!) ฉันคิดว่าฉันยังคงชอบ __PRETTY_FUNCTION__ เมื่อมันมีให้สำหรับการกำหนดขอบเขตแบบพิเศษ

PS:

static string  getScopedClassMethod( string thePrettyFunction )
{
  size_t index = thePrettyFunction . find( "(" );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( index );

  index = thePrettyFunction . rfind( " " );
  if ( index == string::npos )
    return thePrettyFunction;  /* Degenerate case */

  thePrettyFunction . erase( 0, index + 1 );

  return thePrettyFunction;   /* The scoped class name. */
}

2
ยินดีที่ได้ทราบเกี่ยวกับ __PRETTY_FUNCTION__ มีประโยชน์มาก!
Zheng Qu

8

โดยส่วนตัวฉันไม่เต็มใจที่จะใช้สิ่งเหล่านี้เพื่ออะไรยกเว้นการดีบักข้อความ ฉันทำไปแล้ว แต่ฉันพยายามไม่แสดงข้อมูลประเภทนั้นให้กับลูกค้าหรือผู้ใช้ปลายทาง ลูกค้าของฉันไม่ใช่วิศวกรและบางครั้งก็ไม่เข้าใจคอมพิวเตอร์ ฉันอาจบันทึกข้อมูลนี้ไปยังคอนโซล แต่อย่างที่ฉันกล่าวอย่างไม่เต็มใจยกเว้นการดีบักบิวด์หรือเครื่องมือภายใน ฉันคิดว่ามันขึ้นอยู่กับฐานลูกค้าที่คุณมี


29
"ฉันอาจบันทึกข้อมูลนี้ไปยังคอนโซล" - หรือดีกว่า: บันทึกลงในไฟล์เพื่อที่ว่าหากมีสิ่งผิดปกติคุณสามารถขอให้ลูกค้าส่งข้อมูลให้คุณ ...
Christoph

7

C ++ 20 std::source_location

ในที่สุด C ++ ได้เพิ่มตัวเลือกที่ไม่ใช่มาโครและอาจมีอิทธิพลเหนือบางจุดในอนาคตเมื่อ 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!

__PRETTY_FUNCTION__VS __FUNCTION__VS __func__VSstd::source_location::function_name

ตอบแล้วเมื่อ: __PRETTY_FUNCTION__, __FUNCTION__, __func__ แตกต่างกันอย่างไร


1
มีอยู่<experimental/source_location>ในปัจจุบัน gcc-9
陈浩南

5

ฉันใช้พวกเขาตลอดเวลา สิ่งเดียวที่ฉันกังวลคือแจก IP ในล็อกไฟล์ หากชื่อฟังก์ชั่นของคุณดีมากคุณอาจเปิดเผยความลับทางการค้าได้ง่ายขึ้น มันเป็นเหมือนการจัดส่งที่มีสัญลักษณ์การแก้ปัญหาหายากกว่าเท่านั้น ใน 99.999% ของคดีไม่มีอะไรเลวร้ายที่จะเกิดขึ้น


1
จุดดีที่จะนำขึ้น มันเป็นเรื่องธรรมดาที่จะดึงข้อมูลนี้โดยใช้stringsยูทิลิตี้เพื่อดึงข้อมูลเหมือนสตริงทั้งหมดจากปฏิบัติการ แม้แต่ไฟล์บีบอัดที่สามารถบีบอัดได้ก็สามารถแตกได้ ระวังสิ่งที่คุณส่งไปยังเว็บไซต์ลูกค้า บ่อยครั้งที่คู่แข่งสามารถรับมือกับปฏิบัติการของคุณแม้ว่าพวกเขาไม่ควรทำเช่นนั้น
Marty
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.