

ห้องสมุดการยืนยัน C ++ ที่ได้รับการออกแบบมากที่สุด
ปรัชญาห้องสมุด: ให้ข้อมูลการวินิจฉัยที่เป็นประโยชน์มากที่สุด
บางสิ่งที่ยอดเยี่ยมที่ห้องสมุดทำ:
void zoog ( const std::map<std::string, int >& map) {
DEBUG_ASSERT (map. contains ( " foo " ), " expected key not found " , map);
}
ASSERT (vec.size() > min_items(), "vector doesn't have enough items", vec);
std::optional< float > get_param ();
float f = * ASSERT_VAL (get_param());
ประเภทของการยืนยัน:
การยืนยันแบบมีเงื่อนไข:
DEBUG_ASSERT : ตรวจสอบในการดีบัก แต่ แต่ไม่ได้ทำอะไรในการเปิดตัว (คล้ายกับ assert ของห้องสมุดมาตรฐาน)ASSERT : ตรวจสอบทั้งการดีบักและการเปิดตัวASSUME : ตรวจสอบในการดีบักและทำหน้าที่เป็นคำแนะนำการเพิ่มประสิทธิภาพในการเปิดตัวการยืนยันอย่างไม่มีเงื่อนไข:
PANIC : ทริกเกอร์ทั้งในการดีบักและการเปิดตัวUNREACHABLE : ทริกเกอร์ในการดีบักซึ่งไม่สามารถเข้าถึงได้ในการเปิดตัว ชอบ Lowecase assert ?
คุณสามารถเปิดใช้งานตัวพิมพ์เล็ก debug_assert และ assert นามแฝงด้วย -DLIBASSERT_LOWERCASE
สรุปคุณสมบัติ:
ASSERT_EQ ฯลฯDEBUG_ASSERT_VAL และ ASSERT_VAL ตัวแปรที่ส่งคืนค่าเพื่อให้พวกเขาสามารถรวมเข้ากับรหัสได้อย่างราบรื่นเช่น FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr) include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)
# On windows copy libassert.dll to the same directory as the executable for your_target
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif () ตรวจสอบให้แน่ใจว่าได้กำหนดค่าด้วย -DCMAKE_BUILD_TYPE=Debug หรือ -DDCMAKE_BUILD_TYPE=RelWithDebInfo สำหรับสัญลักษณ์และข้อมูลบรรทัด
บน MacOS ขอแนะนำให้สร้างไฟล์. dsym ให้ดูโลจิสติกแพลตฟอร์มด้านล่าง
สำหรับวิธีอื่น ๆ ในการใช้ห้องสมุดเช่นผ่านผู้จัดการแพ็คเกจหรือการติดตั้งทั่วทั้งระบบดูการใช้งานด้านล่าง
โดยพื้นฐานแล้วบทบาทของการยืนยันคือการตรวจสอบสมมติฐานที่เกิดขึ้นในซอฟต์แวร์และระบุการละเมิดที่ใกล้เคียงกับแหล่งที่มาของพวกเขา การยืนยันเครื่องมือควรจัดลำดับความสำคัญให้ข้อมูลและบริบทให้กับนักพัฒนาให้มากที่สุดเท่าที่จะทำได้ น่าเสียดายที่เครื่องมือภาษาและห้องสมุดที่มีอยู่ให้ข้อมูล triage ที่ จำกัด มาก
ตัวอย่างเช่นกับ stdlib ยืนยันการยืนยันเช่น assert(n <= 12); ไม่ให้ข้อมูลเกี่ยวกับความล้มเหลวเกี่ยวกับสาเหตุที่มันล้มเหลวหรือสิ่งที่นำไปสู่ความล้มเหลว การให้ร่องรอยสแต็กและคุณค่าของ n Greatley ช่วยเพิ่มการทดลองและการดีบัก ความล้มเหลวของการยืนยันควรให้ข้อมูลการวินิจฉัยเพียงพอที่โปรแกรมเมอร์ไม่จำเป็นต้องรันใหม่ในดีบักเกอร์เพื่อระบุปัญหา
เวอร์ชัน 1 ของไลบรารีนี้เป็นการสำรวจที่ดูว่าข้อมูลและฟังก์ชั่นที่เป็นประโยชน์สามารถบรรจุลงในการยืนยันได้มากเพียงใดในขณะที่ยังให้อินเทอร์เฟซที่ง่ายและรวดเร็วสำหรับนักพัฒนา
เวอร์ชัน 2 ของห้องสมุดนี้ใช้บทเรียนที่เรียนรู้จากเวอร์ชัน 1 เพื่อสร้างเครื่องมือที่ฉันพบว่าขาดไม่ได้ในการพัฒนา
คุณสมบัติที่สำคัญที่สุดห้องสมุดนี้รองรับคือการสลายตัวของนิพจน์อัตโนมัติ ไม่จำเป็นต้องใช้ ASSERT_LT หรือความยุ่งยากอื่น ๆ assert(vec.size() > 10); เป็นที่เข้าใจโดยอัตโนมัติตามที่แสดงไว้ข้างต้น
ค่าที่เกี่ยวข้องในการแสดงออกของการยืนยันจะปรากฏขึ้น หลีกเลี่ยงการวินิจฉัยซ้ำซ้อนเช่น 2 => 2
DEBUG_ASSERT (map.count( 1 ) == 2);
มีเพียงนิพจน์การยืนยันแบบเต็มเท่านั้นที่สามารถสกัดได้จากการโทรแมโคร การแสดงส่วนใดของนิพจน์ที่สอดคล้องกับค่าที่ต้องการการแยกวิเคราะห์การแสดงออกพื้นฐานบางอย่าง ไวยากรณ์ C ++ นั้นคลุมเครือ แต่การแสดงออกส่วนใหญ่สามารถทำให้ไม่เห็นด้วย
การยืนยันทั้งหมดในไลบรารีสนับสนุนข้อความการวินิจฉัยที่เป็นตัวเลือกเช่นเดียวกับข้อความการวินิจฉัยอื่น ๆ โดยพลการ
FILE* f = ASSERT_VAL(fopen(path, " r " ) != nullptr , " Internal error with foobars " , errno, path); มีการจัดการพิเศษสำหรับ errno และ Strerror จะถูกเรียกโดยอัตโนมัติ
หมายเหตุ: การวินิจฉัยพิเศษได้รับการประเมินเฉพาะในเส้นทางความล้มเหลวของการยืนยัน

มีการทำงานจำนวนมากในการสร้างร่องรอยสแต็กที่สวยงามและจัดรูปแบบให้เป็นไปได้มากที่สุด CPPTRACE ใช้เป็นโซลูชันแบบพกพาและมีอยู่ในตัวเองสำหรับ StackTraces Pre-C ++ 23 การกำหนดค่าเพิ่มเติมสามารถพบได้ในเอกสารของไลบรารี
คุณลักษณะหนึ่งที่น่าสังเกตคือแทนที่จะพิมพ์เส้นทางเต็มรูปแบบเสมอมีเพียงจำนวนไดเรกทอรีขั้นต่ำที่จำเป็นในการพิมพ์เส้นทางที่แยกความแตกต่าง

คุณสมบัติที่คุ้มค่าอีกประการหนึ่งคือการร่องรอยสแต็กจะพับร่องรอยด้วยการเรียกซ้ำลึก:

ตัวจัดการการยืนยันใช้ไวยากรณ์ที่เน้นความเหมาะสมตามที่เห็นในภาพหน้าจอทั้งหมดด้านบน นี่คือเพื่อช่วยเพิ่มความสามารถในการอ่าน
Libassert รองรับตัวจัดการความล้มเหลวของการยืนยันที่กำหนดเอง:
void handler (assert_type type, const assertion_info& assertion) {
throw std::runtime_error ( " Assertion failed: n " + assertion. to_string ());
}
int main () {
libassert::set_failure_handler (handler);
} มีการดูแลอย่างมากในการผลิตการดีบักของค่านิยมอย่างมีประสิทธิภาพที่สุดเท่าที่จะเป็นไปได้: สตริงอักขระตัวเลขควรพิมพ์ตามที่คุณคาดหวัง นอกจากนี้คอนเทนเนอร์, tuples, std :: เป็นทางเลือก, พอยน์เตอร์อัจฉริยะ ฯลฯ ล้วน แต่มีการแสดงข้อมูลให้มากที่สุด หากผู้ใช้งานที่กำหนดประเภทโอเวอร์โหลด operator<<(std::ostream& o, const S& s) การโอเวอร์โหลดนั้นจะถูกเรียก มิฉะนั้นจะมีการพิมพ์ข้อความเริ่มต้น นอกจากนี้ยังมีการจัดให้มีจุดปรับแต่งสตริง:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};

ค่าการยืนยันจะถูกพิมพ์ใน hex หรือ binary รวมถึงทศนิยมถ้า hex/binary ถูกนำมาใช้ทั้งสองด้านของการแสดงออกการยืนยัน:
ASSERT (get_mask() == 0b00001101);
เนื่องจากนิพจน์กำลังถูกย่อยสลายโดยอัตโนมัติคุณสามารถเลือกที่จะทำการเปรียบเทียบที่ไม่ได้เซ็นชื่อเสร็จแล้วโดยอัตโนมัติด้วยความปลอดภัยของป้ายด้วย -DLIBASSERT_SAFE_COMPARISONS :
ASSERT ( 18446744073709551606ULL == - 10 );
libassert ให้สองส่วนหัว <libassert/assert-catch2.hpp> และ <libassert/assert-gtest.hpp> สำหรับใช้กับ catch2 และ googletest
ตัวอย่างเอาต์พุตจาก GTEST:

ข้อมูลเพิ่มเติมด้านล่าง
Libassert มีการยืนยันสามประเภทแต่ละประเภทแตกต่างกันเล็กน้อยขึ้นอยู่กับว่าควรตรวจสอบเมื่อใดและควรตีความอย่างไร:
| ชื่อ | ผล |
|---|---|
DEBUG_ASSERT | ตรวจสอบในการดีบักไม่มี codegen ในการเปิดตัว |
ASSERT | ตรวจสอบทั้งการดีบักและการเปิดตัว |
ASSUME | ตรวจสอบในการดีบัก if(!(expr)) { __builtin_unreachable(); } ในการเปิดตัว |
การยืนยันอย่างไม่มีเงื่อนไข
| ชื่อ | ผล |
|---|---|
PANIC | ทริกเกอร์ทั้งการดีบักและการเปิดตัว |
UNREACHABLE | ทริกเกอร์ในการดีบักมีเครื่องหมายว่าไม่สามารถเข้าถึงได้ในการเปิดตัว |
ประโยชน์อย่างหนึ่งที่ได้รับจาก PANIC และ UNREACHABLE มากกว่า ASSERT(false, ...) คือคอมไพเลอร์ได้รับข้อมูล [[noreturn]]
ASSUME ว่าเป็นเส้นทางที่ล้มเหลวซึ่งไม่สามารถเข้าถึงได้ในการเปิดตัวซึ่งอาจให้ข้อมูลที่เป็นประโยชน์แก่เครื่องมือเพิ่มประสิทธิภาพ นี่ไม่ใช่พฤติกรรมเริ่มต้นสำหรับการยืนยันทั้งหมดเพราะผลที่ตามมาในทันทีคือการยืนยันความล้มเหลวใน -DNDEBUG สามารถนำไปสู่ UB และเป็นการดีกว่าที่จะทำให้สิ่งนี้ชัดเจนมาก
ตัวแปรการยืนยันที่สามารถใช้ในบรรทัดในนิพจน์เช่น FILE* file = ASSERT_VAL(fopen(path, "r"), "Failed to open file"); นอกจากนี้ยังมี:
| ชื่อ | ผล |
|---|---|
DEBUG_ASSERT_VAL | ตรวจสอบในการดีบักจะต้องได้รับการประเมินทั้งในการดีบักและการเปิดตัว |
ASSERT_VAl | ตรวจสอบทั้งการดีบักและการเปิดตัว |
ASSUME_VAL | ตรวจสอบในการดีบัก if(!(expr)) { __builtin_unreachable(); } ในการเปิดตัว |
หมายเหตุ: แม้ในการเปิดตัวการสร้างนิพจน์สำหรับ DEBUG_ASSERT_VAL ยังคงต้องได้รับการประเมินซึ่งแตกต่างจาก DEBUG_ASSERT แน่นอนว่าหากผลลัพธ์ไม่ได้ใช้และไม่มีผลข้างเคียงมันจะได้รับการปรับให้เหมาะสม
ประสิทธิภาพ: เท่าที่ประสิทธิภาพรันไทม์ดำเนินไปผลกระทบที่ Callites นั้นน้อยมากภายใต้ -Og หรือสูงกว่า เส้นทางที่รวดเร็วในรหัส (เช่นที่การยืนยันไม่ล้มเหลว) จะเร็ว ต้องทำงานจำนวนมากเพื่อดำเนินการยืนยันความล้มเหลวเมื่อเกิดขึ้น อย่างไรก็ตามเนื่องจากความล้มเหลวควรหายากสิ่งนี้ไม่ควรสำคัญ
คอมไพล์ความเร็ว: มีค่าใช้จ่ายในการรวบรวมเวลาที่เกี่ยวข้องกับการสร้างอินสแตนซ์เทมเพลตทั้งหมดที่จำเป็นสำหรับเวทมนตร์ของห้องสมุดนี้
อื่น:
บันทึก
เนื่องจากการสลายตัวของนิพจน์ ASSERT(1 = 2); รวบรวม
ฟังก์ชั่นการยืนยันทั้งหมดเป็นมาโคร นี่คือการประกาศหลอกสำหรับการเชื่อมต่อกับพวกเขา:
void DEBUG_ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSUME (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) DEBUG_ASSERT_VAL(expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSERT_VAL (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSUME_VAL (expression, [optional message], [optional extra diagnostics, ...]);
void PANIC ([optional message], [optional extra diagnostics, ...]);
void UNREACHABLE ([optional message], [optional extra diagnostics, ...]); -DLIBASSERT_PREFIX_ASSERTIONS สามารถใช้เพื่อนำหน้ามาโครเหล่านี้ด้วย LIBASSERT_ สิ่งนี้มีประโยชน์สำหรับการห่อหุ้ม libassert
-DLIBASSERT_LOWERCASE สามารถใช้เพื่อเปิดใช้ debug_assert และ assert นามแฝงสำหรับ DEBUG_ASSERT และ ASSERT ดู: แทนที่ <cassert>
expression expression จะถูกย่อยสลายโดยอัตโนมัติเพื่อให้สามารถให้ข้อมูลการวินิจฉัยได้ ประเภทผลลัพธ์จะต้องแปลงสภาพเป็นบูลีน
การดำเนินการระหว่างด้านซ้ายและด้านขวาของการดำเนินการระดับบนสุดในแผนผังการแสดงออกได้รับการประเมินโดยวัตถุฟังก์ชัน
หมายเหตุ: ตัวดำเนินการตรรกะบูลีน ( && และ || ) จะไม่ถูกย่อยสลายโดยค่าเริ่มต้นเนื่องจากการหมุนเวียนสั้น
assertion message อาจมีข้อความยืนยันทางเลือก หากอาร์กิวเมนต์แรกหลังจากนิพจน์การยืนยันหรืออาร์กิวเมนต์แรกในความตื่นตระหนก/ไม่สามารถเข้าถึงได้เป็นประเภทสตริงใด ๆ มันจะถูกใช้เป็นข้อความ (ถ้าคุณต้องการพารามิเตอร์แรกซึ่งเกิดขึ้นเป็นสตริงเป็นค่าการวินิจฉัย ASSERT(foo, "", str); แทนเพียงแค่ผ่านสตริงว่างก่อน
หมายเหตุ: นิพจน์ข้อความยืนยันได้รับการประเมินเฉพาะในเส้นทางความล้มเหลวของการยืนยัน
extra diagnosticsอาจมีการให้ค่าการวินิจฉัยเพิ่มเติมจำนวนมากขึ้น สิ่งเหล่านี้จะแสดงอยู่ด้านล่างการวินิจฉัยนิพจน์หากการตรวจสอบล้มเหลว
หมายเหตุ: การวินิจฉัยพิเศษจะถูกประเมินเฉพาะในเส้นทางความล้มเหลวของการยืนยัน
มีการจัดการพิเศษเมื่อมีการจัดเตรียม errno : ค่าของ strerror จะปรากฏขึ้นโดยอัตโนมัติ
เพื่ออำนวยความสะดวกในการรวมความสะดวกในการรวมเข้ากับรหัส _VAL มีให้ซึ่งส่งคืนค่าจากนิพจน์การยืนยัน ค่าที่ส่งคืนจะถูกกำหนดดังนี้:
ASSERT_VAL(foo()); หรือ ASSERT_VAL(false); ) ในนิพจน์การยืนยันค่าของนิพจน์จะถูกส่งคืน== ,! != , < , <= , > , >= , && , || หรือหรือการมอบหมายหรือการมอบหมายใด ๆ จากนั้นค่าของ ตัวถูกดำเนินการทางซ้าย จะถูกส่งคืน& , | , ^ , << , >> หรือผู้ประกอบการไบนารีที่มีความสำคัญเหนือกว่า bitshift จากนั้นค่าของการแสดงออกทั้งหมดจะถูกส่งกลับ เช่น ASSERT_VAL(foo() > 2); ส่งคืนผลลัพธ์ที่คำนวณจาก foo() และ ASSERT_VAL(x & y); ส่งคืนผลลัพธ์ที่คำนวณได้ของ x & y ;
หากค่าจากนิพจน์การยืนยันที่เลือกที่จะส่งคืนคือ lvalue ประเภทของการเรียกการยืนยันจะเป็นการอ้างอิง lvalue หากค่าจากนิพจน์การยืนยันเป็น rvalue ประเภทของการโทรจะเป็น rvalue
namespace libassert {
[[nodiscard]] std::string stacktrace (
int width = 0 ,
const color_scheme& scheme = get_color_scheme(),
std::size_t skip = 0
);
template < typename T> [[nodiscard]] std::string_view type_name () noexcept ;
template < typename T> [[nodiscard]] std::string pretty_type_name () noexcept ;
template < typename T> [[nodiscard]] std::string stringify ( const T& value);
}stacktrace : สร้างร่องรอยสแต็กรูปแบบตามความกว้างที่กำหนด (0 โดยไม่มีการจัดรูปแบบความกว้าง)type_name : ส่งคืนชื่อประเภทของ tpretty_type_name : ส่งคืนชื่อประเภท prettified สำหรับ tstringify : สร้างสตริงการดีบักของค่า namespace libassert {
void enable_virtual_terminal_processing_if_needed ();
inline constexpr int stdin_fileno = 0 ;
inline constexpr int stdout_fileno = 1 ;
inline constexpr int stderr_fileno = 2 ;
bool isatty ( int fd);
[[nodiscard]] int terminal_width ( int fd);
}enable_virtual_terminal_processing_if_needed : เปิดใช้งานลำดับ ANSI Escape สำหรับเทอร์มินัลบน Windows ซึ่งจำเป็นสำหรับเอาต์พุตสีisatty : ส่งคืนจริงถ้าตัวอธิบายไฟล์สอดคล้องกับเทอร์มินัลterminal_width : ส่งคืนความกว้างของเทอร์มินัลที่แสดงโดย FD หรือ 0 ในข้อผิดพลาด namespace libassert {
// NOTE: string view underlying data should have static storage duration, or otherwise live as
// long as the scheme is in use
struct color_scheme {
std::string_view string, escape, keyword, named_literal, number, punctuation, operator_token,
call_identifier, scope_resolution_identifier, identifier, accent, unknown, reset;
static const color_scheme ansi_basic;
static const color_scheme ansi_rgb;
static const color_scheme blank;
};
void set_color_scheme ( const color_scheme&);
const color_scheme& get_color_scheme ();
} โดยค่าเริ่มต้น color_scheme::ansi_rgb ใช้ ในการปิดใช้งานสีให้ใช้ color_scheme::blank
set_color_scheme : ตั้งค่าโทนสีสำหรับตัวจัดการการยืนยันเริ่มต้นเมื่อ stderr เป็นเทอร์มินัล namespace libassert {
void set_separator (std::string_view separator);
}set_separator : ตั้งค่าตัวคั่นระหว่างนิพจน์และค่าในเอาต์พุตการวินิจฉัยการยืนยัน ค่าเริ่มต้น: => หมายเหตุ: ไม่ต้องใช้เธรดที่ปลอดภัย namespace libassert {
enum class literal_format_mode {
infer, // infer literal formats based on the assertion condition
no_variations, // don't do any literal format variations, just default
fixed_variations // always use a fixed set of formats (in addition to the default format)
};
void set_literal_format_mode (literal_format_mode);
enum class literal_format : unsigned {
// integers and floats are decimal by default, chars are of course chars, and everything
// else only has one format that makes sense
default_format = 0 ,
integer_hex = 1 ,
integer_octal = 2 ,
integer_binary = 4 ,
integer_character = 8 , // format integers as characters and characters as integers
float_hex = 16 ,
};
[[nodiscard]] constexpr literal_format operator |(literal_format a, literal_format b);
void set_fixed_literal_format (literal_format);
}set_literal_format_mode : ตั้งค่าว่าไลบรารีควรแสดงรูปแบบที่แท้จริงหรืออนุมานset_fixed_literal_format : ตั้งค่าการกำหนดค่ารูปแบบตัวอักษรคงที่เปลี่ยนค่า literal_format_mode โดยอัตโนมัติ โปรดทราบว่ารูปแบบเริ่มต้นจะถูกใช้ร่วมกับผู้อื่นเสมอ namespace libassert {
enum class path_mode {
full, // full path is used
disambiguated, // only enough folders needed to disambiguate are provided
basename, // only the file name is used
};
LIBASSERT_EXPORT void set_path_mode (path_mode mode);
}set_path_mode : ตั้งค่าโหมดการย่อพา ธ สำหรับเอาต์พุตการยืนยัน ค่าเริ่มต้น: path_mode::disambiguated namespace libassert {
enum class assert_type {
debug_assertion,
assertion,
assumption,
panic,
unreachable
};
struct LIBASSERT_EXPORT binary_diagnostics_descriptor {
std::string left_expression;
std::string right_expression;
std::string left_stringification;
std::string right_stringification;
};
struct extra_diagnostic {
std::string_view expression;
std::string stringification;
};
struct LIBASSERT_EXPORT assertion_info {
std::string_view macro_name;
assert_type type;
std::string_view expression_string;
std::string_view file_name;
std:: uint32_t line;
std::string_view function;
std::optional<std::string> message;
std::optional<binary_diagnostics_descriptor> binary_diagnostics;
std::vector<extra_diagnostic> extra_diagnostics;
size_t n_args;
std::string_view action () const ;
const cpptrace::raw_trace& get_raw_trace () const ;
const cpptrace::stacktrace& get_stacktrace () const ;
[[nodiscard]] std::string header ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string tagline ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string location () const ;
[[nodiscard]] std::string statement ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_binary_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_extra_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_stacktrace ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string to_string ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
};
} Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Debug Assertion failed : assertion_info.action()demo.cpp:194 : assertion_info.file_name และ assertion_info.linevoid foo::baz() : assertion_info.pretty_functionInternal error with foobars : assertion_info.messagedebug_assert : assertion_info.macro_nameopen(path, 0) >= 0 : assertion_info.expression_string... : กำหนดโดย assertion_info.n_args ซึ่งมีจำนวนอาร์กิวเมนต์ทั้งหมดที่ส่งผ่านไปยังแมโครยืนยันopen(path, 0) : assertion_info.binary_diagnostics.left_expression-1 : assertion_info.binary_diagnostics.left_stringification0 => 0 ไม่มีประโยชน์)errno : assertion_info.extra_diagnostics[0].expression2 "No such file or directory" : assertion_info.extra_diagnostics[0].stringificationassertion_info.get_stacktrace() หรือ assertion_info.get_raw_trace() เพื่อรับการติดตามโดยไม่ต้องแก้ไขผู้ช่วย:
assertion_info.header() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.tagline() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
assertion_info.location() :
บันทึก
การประมวลผลเส้นทางจะดำเนินการตามโหมดเส้นทาง
demo.cpp:194
assertion_info.statement() :
debug_assert(open(path, 0) >= 0, ...);
assertion_info.print_binary_diagnostics() :
Where:
open(path, 0) => -1
assertion_info.print_extra_diagnostics() :
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.print_stacktrace() :
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Libassert จัดเตรียมจุดปรับแต่งสำหรับประเภทที่ผู้ใช้กำหนด:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};โดยค่าเริ่มต้นทุกประเภทที่ผู้ใช้ที่กำหนดไว้จะสามารถสตริงได้โดยอัตโนมัติ
นอกจากนี้ LIBASSERT_USE_FMT สามารถใช้เพื่อให้ libassert ใช้ fmt::formatter s
สุดท้ายประเภทใด ๆ ที่มี operator<< โอเวอร์โหลดสามารถ stringified
namespace libassert {
void set_failure_handler ( void (*handler)( const assertion_info&));
}set_failure_handler : ตั้งค่าตัวจัดการการยืนยันสำหรับโปรแกรมตัวอย่างตัวจัดการการยืนยันคล้ายกับตัวจัดการเริ่มต้น:
void libassert_default_failure_handler ( const assertion_info& info) {
libassert::enable_virtual_terminal_processing_if_needed (); // for terminal colors on windows
std::string message = info. to_string (
libassert::terminal_width (libassert::stderr_fileno),
libassert::isatty (libassert::stderr_fileno)
? libassert::get_color_scheme ()
: libassert::color_scheme::blank
);
std::cerr << message << std::endl;
switch (info. type ) {
case libassert::assert_type::assertion:
case libassert::assert_type::debug_assertion:
case libassert::assert_type::assumption:
case libassert::assert_type::panic:
case libassert::assert_type::unreachable:
( void ) fflush (stderr);
std::abort ();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a
// debug build of this library
break ;
default :
std::cerr << " Critical error: Unknown libassert::assert_type " << std::endl;
std::abort ( 1 );
}
}โดยค่าเริ่มต้น libassert ยกเลิกจากทุกประเภทการยืนยัน อย่างไรก็ตามอาจเป็นที่พึงปรารถนาที่จะโยนข้อยกเว้นจากประเภทการยืนยันบางประเภทหรือทั้งหมดแทนที่จะทำแท้ง
สำคัญ
ตัวจัดการความล้มเหลวจะต้องไม่กลับมาสำหรับ assert_type::panic และ assert_type::unreachable
Libassert รองรับจุดพักโปรแกรมเกี่ยวกับความล้มเหลวในการยืนยันเพื่อยืนยันการยืนยันมากขึ้นเป็นมิตรกับดีบัก

ฟังก์ชั่นนี้มีการเลือกใช้และสามารถเปิดใช้งานได้โดยการกำหนด LIBASSERT_BREAK_ON_FAIL สิ่งนี้ทำได้ดีที่สุดเป็นธงคอมไพเลอร์: -DLIBASSERT_BREAK_ON_FAIL หรือ /DLIBASSERT_BREAK_ON_FAIL
ภายในห้องสมุดจะตรวจสอบการดีบักเกอร์ก่อนที่จะดำเนินการคำสั่งเพื่อทำลายข้อบกพร่อง โดยค่าเริ่มต้นการตรวจสอบจะดำเนินการเพียงครั้งเดียวในความล้มเหลวในการยืนยันครั้งแรก ในบางสถานการณ์อาจเป็นที่พึงปรารถนาที่จะกำหนดค่าการตรวจสอบนี้ให้ดำเนินการเสมอเช่นหากคุณใช้ตัวจัดการการยืนยันที่กำหนดเองที่โยนข้อยกเว้นแทนการยกเลิกและคุณอาจกู้คืนจากความล้มเหลวของการยืนยันที่อนุญาตให้ล้มเหลวเพิ่มเติมในภายหลัง คุณสามารถใช้ libassert::set_debugger_check_mode เพื่อควบคุมวิธีการตรวจสอบนี้:
namespace libassert {
enum class debugger_check_mode {
check_once,
check_every_time,
};
void set_debugger_check_mode (debugger_check_mode mode) noexcept ;
}ห้องสมุดยังเปิดเผยยูทิลิตี้ภายในสำหรับการตั้งค่าเบรกพอยต์และตรวจสอบว่าโปรแกรมกำลังดีบั๊กหรือไม่:
namespace libassert {
bool is_debugger_present () noexcept ;
}
# define LIBASSERT_BREAKPOINT () <...internals...>
# define LIBASSERT_BREAKPOINT_IF_DEBUGGING () <...internals...>API นี้เลียนแบบ API ของ P2514 ซึ่งได้รับการยอมรับจาก C ++ 26
หมายเหตุเกี่ยวกับ constexpr : สำหรับ Clang และ MSVC Libassert สามารถใช้คอมไพเลอร์ Intrinsics อย่างไรก็ตามสำหรับการประกอบอินไลน์ GCC เป็นสิ่งจำเป็น ไม่อนุญาตให้ใช้แอสเซมบลีแบบอินไลน์ในฟังก์ชั่น constexpr pre-c ++ 20 อย่างไรก็ตาม GCC รองรับด้วยคำเตือนหลังจาก GCC 10 และห้องสมุดสามารถทำลายได้ว่าคำเตือนสำหรับ GCC 12
กำหนด:
LIBASSERT_USE_MAGIC_ENUM : ใช้ magic enum สำหรับค่า enum stringifyingLIBASSERT_DECOMPOSE_BINARY_LOGICAL : decompose && และ ||LIBASSERT_SAFE_COMPARISONS : เปิดใช้งานการเปรียบเทียบที่ไม่ได้เซ็นชื่ออย่างปลอดภัยสำหรับการแสดงออกที่สลายตัวLIBASSERT_PREFIX_ASSERTIONS : คำนำหน้าแมโครการยืนยันทั้งหมดด้วย LIBASSERT_LIBASSERT_USE_FMT : เปิดใช้งานการรวม libfmtLIBASSERT_NO_STRINGIFY_SMART_POINTER_OBJECTS : ปิดใช้งานสตริงของเนื้อหาตัวชี้อัจฉริยะcmake:
LIBASSERT_USE_EXTERNAL_CPPTRACE : ใช้ externam cpptrace แทนการจัดไลบรารีด้วย fetchContentLIBASSERT_USE_EXTERNAL_MAGIC_ENUM : ใช้ enum magic externam แทนการจัดไลบรารีด้วย fetchContentบันทึก
เนื่องจากตัวประมวลผลล่วงหน้าที่ไม่เป็นไปได้ของ MSVC จึงไม่มีวิธีง่ายๆในการจัดหาผู้ห่อหุ้มการยืนยัน เพื่อใช้การรวมไลบรารีการทดสอบ /Zc:preprocessor
libassert ให้การรวม catch2 ใน libassert/assert-catch2.hpp :
# include < libassert/assert-catch2.hpp >
TEST_CASE ( " 1 + 1 is 2 " ) {
ASSERT ( 1 + 1 == 3 );
}
ปัจจุบันแมโครเพียงอย่างเดียวที่ให้ไว้คือ ASSERT ซึ่งจะดำเนิน REQUIRE ภายใน
หมายเหตุ: ก่อนที่ V3.6.0 รหัสสี ANSI จะรบกวนการห่อเส้นของ Catch2 ดังนั้นสีจึงถูกปิดใช้งานในเวอร์ชันเก่า
libassert ให้การรวม GTest ใน libassert/assert-gtest.hpp :
# include < libassert/assert-gtest.hpp >
TEST (Addition, Arithmetic) {
ASSERT ( 1 + 1 == 3 );
}
ปัจจุบัน Libassert ให้ ASSERT และ EXPECT มาโครสำหรับ GTEST
สิ่งนี้ไม่ได้สวยเท่าที่ฉันต้องการ แต่มันทำให้งานเสร็จ
ห้องสมุดนี้มีเป้าหมาย> = C ++ 17 และรองรับคอมไพเลอร์ที่สำคัญทั้งหมดและแพลตฟอร์มหลักทั้งหมด (Linux, MacOS, Windows และ MingW)
หมายเหตุ: ไลบรารีใช้ส่วนขยายคอมไพเลอร์และคุณสมบัติเฉพาะของคอมไพเลอร์ดังนั้นจึงไม่สามารถใช้งานได้กับ -pedantic
ด้วย cmake fetchcontent:
include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)หมายเหตุ: บน Windows และ MacOS แนะนำให้ใช้งานพิเศษบางอย่างดูที่แพลตฟอร์มโลจิสติกด้านล่าง
ตรวจสอบให้แน่ใจว่าได้กำหนดค่าด้วย -DCMAKE_BUILD_TYPE=Debug หรือ -DDCMAKE_BUILD_TYPE=RelWithDebInfo สำหรับสัญลักษณ์และข้อมูลบรรทัด
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j
sudo make installใช้ผ่าน cmake:
find_package (libassert REQUIRED)
target_link_libraries (<your target > libassert::assert) ตรวจสอบให้แน่ใจว่าได้กำหนดค่าด้วย -DCMAKE_BUILD_TYPE=Debug หรือ -DDCMAKE_BUILD_TYPE=RelWithDebInfo สำหรับสัญลักษณ์และข้อมูลบรรทัด
หรือรวบรวมด้วย -lassert :
g++ main.cpp -o main -g -Wall -lassert
./mainหากคุณได้รับข้อผิดพลาดตามสายของ
error while loading shared libraries: libassert.so: cannot open shared object file: No such file or directory
คุณอาจต้องเรียกใช้ sudo /sbin/ldconfig เพื่อสร้างลิงก์ที่จำเป็นและอัปเดตแคชเพื่อให้ระบบสามารถค้นหา libcpptrace.o (ฉันต้องทำสิ่งนี้ใน Ubuntu) เฉพาะเมื่อติดตั้งทั่วทั้งระบบ โดยปกติแล้วผู้จัดการแพ็คเกจของคุณจะทำสิ่งนี้ให้คุณเมื่อติดตั้งไลบรารีใหม่
git clone https: // github.com / jeremy - rifkin / libassert.git
git checkout v2. 1.2
mkdir libassert / build
cd libassert / build
cmake . . - DCMAKE_BUILD_TYPE = Release
msbuild libassert.sln
msbuild INSTALL.vcxprojหมายเหตุ: คุณจะต้องทำงานเป็นผู้ดูแลระบบใน PowerShell นักพัฒนาหรือใช้ vcvarsall.bat กระจายกับ Visual Studio เพื่อรับตัวแปรสภาพแวดล้อมที่ถูกต้อง
หากต้องการติดตั้งสำหรับผู้ใช้ในพื้นที่ (หรือคำนำหน้าแบบกำหนดเอง):
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= $HOME /wherever
make -j
sudo make installใช้ผ่าน cmake:
find_package (libassert REQUIRED PATHS $ENV{HOME} /wherever)
target_link_libraries (<your target > libassert::assert)ใช้ด้วยตนเอง:
g++ main.cpp -o main -g -Wall -I$HOME/wherever/include -L$HOME/wherever/lib -lassert
หากต้องการใช้ไลบรารีโดยไม่ต้องใช้ CMake ก่อนที่จะทำตามคำแนะนำการติดตั้งที่การติดตั้งทั่วทั้งระบบการติดตั้งผู้ใช้ในท้องถิ่นหรือผู้จัดการแพ็คเกจ
ใช้อาร์กิวเมนต์ต่อไปนี้เพื่อรวบรวมด้วย libassert:
| ผู้ประกอบการ | แพลตฟอร์ม | การพึ่งพาอาศัยกัน |
|---|---|---|
| GCC, Clang, Intel, ฯลฯ | linux/macOS/unix | -libassert -I[path] [cpptrace args] |
| Mingw | หน้าต่าง | -libassert -I[path] [cpptrace args] |
| MSVC | หน้าต่าง | assert.lib /I[path] [cpptrace args] |
| เสียงดัง | หน้าต่าง | -libassert -I[path] [cpptrace args] |
สำหรับ [path] ตัวยึดใน -I[path] และ /I[path] ให้ระบุเส้นทางไปยังโฟลเดอร์รวมที่มี libassert/assert.hpp
หากคุณกำลังเชื่อมโยงแบบคงที่คุณจะต้องระบุ -DLIBASSERT_STATIC_DEFINE เพิ่มเติม
สำหรับตัวยึดตำแหน่ง [cpptrace args] อ้างถึงเอกสาร CPPTRACE
Libassert มีให้บริการผ่าน Conan ที่ https://conan.io/center/recipes/libassert
[requires]
libassert/2.1.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# ...
find_package (libassert REQUIRED)
# ...
target_link_libraries (YOUR_TARGET libassert::assert) vcpkg install libassert
find_package (libassert CONFIG REQUIRED)
target_link_libraries (YOUR_TARGET PRIVATE libassert::assert)Windows และ MacOS ต้องการงานพิเศษเล็กน้อยเพื่อให้ได้ทุกอย่างในสถานที่ที่เหมาะสม
การคัดลอกไลบรารี. dll บน windows:
# Copy the assert.dll on windows to the same directory as the executable for your_target.
# Not required if static linking.
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif ()บน MacOS ขอแนะนำให้สร้างไฟล์ DSYM ที่มีข้อมูลการดีบักสำหรับโปรแกรมของคุณ:
ใน xcode cmake สามารถทำได้ด้วย
set_target_properties (your_target PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" ) และภายนอก xcode สามารถทำได้ด้วย dsymutil yourbinary :
# Create a .dSYM file on macos. Currently required, but hopefully not for long
if ( APPLE )
add_custom_command (
TARGET your_target
POST_BUILD
COMMAND dsymutil $<TARGET_FILE:your_target>
)
endif () ไลบรารีนี้ไม่ได้เปลี่ยนแบบเลื่อนลงสำหรับ <cassert> -DLIBASSERT_LOWERCASE สามารถใช้เพื่อสร้างนามแฝงตัวพิมพ์เล็กสำหรับแมโครการยืนยัน แต่โปรดทราบว่า ASSERT ของ Libassert ยังคงตรวจสอบในการเปิดตัว หากต้องการแทนที่ <cassert> ใช้กับ libassert ให้แทนที่ assert ด้วย DEBUG_ASSERT หรือสร้างนามแฝงตามบรรทัดต่อไปนี้:
# define assert (...) DEBUG_ASSERT(__VA_ARGS__) สิ่งหนึ่งที่ต้องระวัง: assert ของ Cassert Overriding นั้นไม่ได้รับอนุญาตทางเทคนิคโดยมาตรฐาน แต่สิ่งนี้ไม่ควรเป็นปัญหาสำหรับคอมไพเลอร์ที่มีสติ
ไม่ยังไม่
cpp-sort ของ Morwenn แม้จะมีสิ่งก่อสร้างเช่น assert_eq การวินิจฉัยการยืนยันมักจะขาด ตัวอย่างเช่นในสนิมค่าซ้ายและขวาจะปรากฏขึ้น แต่ไม่ใช่การแสดงออกของตัวเอง:
fn main ( ) {
let count = 4 ;
assert_eq ! ( count , 2 ) ;
} thread 'main' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `2`', /app/example.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
สิ่งนี้ไม่เป็นประโยชน์เท่าที่ควร
ฟังก์ชั่นภาษาอื่น ๆ / ไลบรารีมาตรฐานของพวกเขาให้:
| C/C ++ | สนิม | C# | ชวา | งูหลาม | จาวาสคริปต์ | libassert | |
|---|---|---|---|---|---|---|---|
| สตริงนิพจน์ | |||||||
| ที่ตั้ง | |||||||
| สแต็คร่องรอย | |||||||
| ข้อความยืนยัน | - | ||||||
| การวินิจฉัยพิเศษ | - | - | - | - | |||
| ความเชี่ยวชาญแบบไบนารี | |||||||
| การสลายตัวของนิพจน์อัตโนมัติ | |||||||
| สตริงย่อยการแสดงออก |
* : เป็นไปได้ผ่านการจัดรูปแบบสตริง แต่นั่นเป็นแบบย่อย
** : assert(expression && "message") มักใช้กันทั่วไป แต่นี่เป็นแบบย่อยและอนุญาตให้ใช้ข้อความตามตัวอักษรสตริงเท่านั้น
ความพิเศษ:
| C/C ++ | สนิม | C# | ชวา | งูหลาม | จาวาสคริปต์ | libassert | |
|---|---|---|---|---|---|---|---|
| การไฮไลต์ไวยากรณ์ | - | ||||||
| การจัดรูปแบบความสอดคล้องตามตัวอักษร | |||||||
| สตริงการแสดงออกและค่าการแสดงออกทุกที่ | |||||||
| ส่งคืนค่าจากการยืนยันเพื่ออนุญาตให้ยืนยันการรวมเข้ากับนิพจน์แบบอินไลน์ |