

مكتبة تأكيد 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 : مشغلات في التصحيح ، والتي تم وضع علامة عليها على أنها لا يمكن الوصول إليها في الإصدار تفضل assert LoweCase؟
يمكنك تمكين 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 ، راجع اللوجستيات الأساسية أدناه.
للحصول على طرق أخرى لاستخدام المكتبة ، مثل مديري الحزم أو التثبيت على مستوى النظام ، راجع الاستخدام أدناه.
في الأساس دور التأكيدات هو التحقق من الافتراضات المقدمة في البرمجيات وتحديد الانتهاكات القريبة من مصادرها. يجب أن تعطي أدوات التأكيد أولوية توفير أكبر قدر ممكن من المعلومات والسياق للمطور للسماح بالفرز السريع. لسوء الحظ ، توفر أدوات اللغة والمكتبة الحالية معلومات محدودة للغاية.
على سبيل المثال مع تأكيدات 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) فسيتم استدعاء هذا الحمل الزائد. وإلا فإنها سيتم طباعة رسالة افتراضية. بالإضافة إلى ذلك ، يتم توفير نقطة تخصيص structioniztaion:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};

تتم طباعة قيم التأكيد في Hex أو ثنائية وكذلك عشرية إذا تم استخدام 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 | تم التحقق من تصحيح الأخطاء ، لا يوجد رمز في الإصدار |
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 . بالطبع ، إذا كانت النتيجة غير مستخدمة ولم تنتج أي آثار جانبية ، فسيتم تحسينها بعيدًا.
الأداء: فيما يتعلق بأداء وقت التشغيل ، يكون التأثير في المكالمات ضئيلًا جدًا -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 : إرجاع اسم النوع المتجمل لـ 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 للأطراف على 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 : قم بتعيين تكوين تنسيق حرفي ثابت ، ويغير تلقائيًا الحصرية _mord_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 and 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<< overload.
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...>تحاكي واجهة برمجة التطبيقات هذه واجهة برمجة تطبيقات P2514 ، والتي تم قبولها على C ++ 26.
ملاحظة حول constexpr : بالنسبة إلى Clang و MSVC Libassert يمكن استخدامه ، ومع ذلك ، مطلوب لتجميع GCC INLINE. لا يُسمح بالتجميع المضمّن في وظائف Constexpr Pre-C ++ 20 ، ومع ذلك ، تدعمها GCC مع تحذير بعد GCC 10 ويمكن للمكتبة أن تنطلق من تحذير GCC 12.
يعرّف:
LIBASSERT_USE_MAGIC_ENUM : استخدم التعداد السحري لتجهيز قيم التعدادLIBASSERT_DECOMPOSE_BINARY_LOGICAL : تحلل && و ||LIBASSERT_SAFE_COMPARISONS : تمكين مقارنات آمنة موقعة غير مصممة للتعبيرات المتحللةLIBASSERT_PREFIX_ASSERTIONS : بادئة جميع وحدات الماكرو للتأكيد مع LIBASSERT_LIBASSERT_USE_FMT : تمكين تكامل libfmtLIBASSERT_NO_STRINGIFY_SMART_POINTER_OBJECTS : تعطيل سلسلة محتويات المؤشر الذكيCmake:
LIBASSERT_USE_EXTERNAL_CPPTRACE : استخدم cpptrace الخارجي بدلاً من التمسك بالمكتبة مع FetchContentLIBASSERT_USE_EXTERNAL_MAGIC_ENUM : استخدم التعداد السحري الخارجي بدلاً من تناول المكتبة مع 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.so (اضطررت إلى القيام بذلك على 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 غير مسموح به من الناحية الفنية من خلال المعيار ، ولكن لا ينبغي أن يكون هذا مشكلة لأي مترجم عاقل.
لا ، ليس بعد.
cpp-sort حتى مع وجود بنيات مثل 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 ++ | الصدأ | ج# | جافا | بيثون | جافا سكريبت | libassert | |
|---|---|---|---|---|---|---|---|
| سلسلة التعبير | ✔ | ✔ | |||||
| موقع | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| تتبع المكدس | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| رسالة التأكيد | ** | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| تشخيصات إضافية | * | * | * | * | ✔ | ||
| التخصصات الثنائية | ✔ | ✔ | ✔ | ||||
| تحلل التعبير التلقائي | ✔ | ||||||
| سلاسل التعبير الفرعي | ✔ |
* : ممكن من خلال تنسيق السلسلة ولكن هذا مثالي دون.
** : يتم استخدام assert(expression && "message") بشكل شائع ، لكن هذا مثالي دون مثالي ويسمح فقط للرسائل الحرفية بالسلسلة.
إضافات:
| C/C ++ | الصدأ | ج# | جافا | بيثون | جافا سكريبت | libassert | |
|---|---|---|---|---|---|---|---|
| بناء جملة تسليط الضوء | ؟ | ✔ | |||||
| تنسيق التنسيق الحرفي | ✔ | ||||||
| سلاسل التعبير وقيم التعبير في كل مكان | ✔ | ||||||
| قيم الإرجاع من التأكيد للسماح بدمج التأكيدات في التعبيرات المضمنة | ✔ |