ฉันกำลังศึกษาบทเรียนของ OpenCV และพบกับassert
ฟังก์ชั่น; มันทำอะไร?
ฉันกำลังศึกษาบทเรียนของ OpenCV และพบกับassert
ฟังก์ชั่น; มันทำอะไร?
คำตอบ:
assert
จะยุติโปรแกรม (โดยปกติจะมีข้อความที่อ้างถึงคำสั่ง assert) หากการโต้แย้งของมันกลายเป็นเท็จ โดยทั่วไปจะใช้ในระหว่างการดีบักเพื่อให้โปรแกรมล้มเหลวอย่างชัดเจนยิ่งขึ้นหากเกิดเหตุการณ์ที่ไม่คาดคิด
ตัวอย่างเช่น:
assert(length >= 0); // die if length is negative.
คุณยังสามารถเพิ่มข้อความที่ให้ข้อมูลเพิ่มเติมเพื่อแสดงถ้ามันล้มเหลวเช่น:
assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");
หรืออย่างอื่นเช่นนี้:
assert(("Length can't possibly be negative! Tell jsmith", length >= 0));
เมื่อคุณทำบิลด์ (ไม่ใช่ debug) คุณสามารถลบโอเวอร์เฮดของการประเมินผลassert
ข้อความโดยกำหนดNDEBUG
แมโครโดยปกติแล้วจะมีคอมไพเลอร์สวิทช์ ข้อสรุปของสิ่งนี้คือโปรแกรมของคุณไม่ควรเชื่อถือการทำงานของแมโครยืนยัน
// BAD
assert(x++);
// GOOD
assert(x);
x++;
// Watch out! Depends on the function:
assert(foo());
// Here's a safer way:
int ret = foo();
assert(ret);
จากการรวมกันของโปรแกรมเรียกยกเลิก () และไม่ได้รับประกันว่าจะทำอะไรยืนยันควรจะใช้เพื่อทดสอบสิ่งที่นักพัฒนาได้สันนิษฐานมากกว่าตัวอย่างเช่นผู้ใช้ป้อนตัวเลขมากกว่าตัวอักษร (ซึ่งควรจะเป็น จัดการโดยวิธีอื่น)
assert
มักจะทำให้เกิดข้อยกเว้น" - ใน C ++ มันจะไม่เพิ่มขึ้น "ยกเว้น" มันเรียกว่ายกเลิก ... มันแตกต่างกันเล็กน้อย
#
ตัวละครไม่แนะนำความคิดเห็น
assert("error message", expression)
ยืนยันคำสั่งคอมพิวเตอร์จะคล้ายคลึงกับคำสั่งให้แน่ใจว่าในภาษาอังกฤษ
ลองดูที่
โปรแกรมตัวอย่าง assert () ใน C ++
คอมไพเลอร์จำนวนมากเสนอมาโคร assert () แมโคร assert () ส่งคืน TRUE หากพารามิเตอร์ประเมิน TRUE และดำเนินการบางอย่างถ้าประเมิน FALSE คอมไพเลอร์จำนวนมากจะยกเลิกโปรแกรมบน assert () ที่ล้มเหลว คนอื่นจะโยนข้อยกเว้น
คุณลักษณะที่มีประสิทธิภาพอย่างหนึ่งของแมโคร assert () คือตัวประมวลผลก่อนยุบลงในโค้ดที่ไม่มีเลยหากไม่ได้กำหนด DEBUG มันเป็นความช่วยเหลือที่ยอดเยี่ยมในระหว่างการพัฒนาและเมื่อผลิตภัณฑ์ขั้นสุดท้ายจัดส่งไม่มีการปรับประสิทธิภาพหรือเพิ่มขนาดของเวอร์ชันโปรแกรมที่เรียกใช้งานได้
เช่น
#include <stdio.h>
#include <assert.h>
void analyze (char *, int);
int main(void)
{
char *string = "ABC";
int length = 3;
analyze(string, length);
printf("The string %s is not null or empty, "
"and has length %d \n", string, length);
}
void analyze(char *string, int length)
{
assert(string != NULL); /* cannot be NULL */
assert(*string != '\0'); /* cannot be empty */
assert(length > 0); /* must be positive */
}
/**************** Output should be similar to ******************
The string ABC is not null or empty, and has length 3
ฟังก์ชั่น assert () สามารถวินิจฉัยข้อบกพร่องของโปรแกรม ใน C มันถูกกำหนดไว้ใน<assert.h>
และใน C ++ <cassert>
มันถูกกำหนดไว้ใน ต้นแบบของมันคือ
void assert(int expression);
นิพจน์อาร์กิวเมนต์สามารถเป็นอะไรก็ได้ที่คุณต้องการทดสอบ - ตัวแปรหรือนิพจน์ C ใด ๆ ถ้า expression ประเมินค่าเป็น TRUE assert () จะไม่ทำอะไรเลย หาก expression ประเมินค่าเป็น FALSE assert () จะแสดงข้อความแสดงข้อผิดพลาดบน stderr และยกเลิกการทำงานของโปรแกรม
คุณใช้ assert () อย่างไร? มันถูกใช้บ่อยที่สุดในการติดตามข้อบกพร่องของโปรแกรม (ซึ่งแตกต่างจากข้อผิดพลาดในการรวบรวม) ข้อผิดพลาดไม่ได้ป้องกันโปรแกรมจากการรวบรวม แต่มันทำให้มันให้ผลลัพธ์ที่ไม่ถูกต้องหรือทำงานไม่ถูกต้อง (ล็อคเช่น) ตัวอย่างเช่นโปรแกรมวิเคราะห์ทางการเงินที่คุณเขียนอาจให้คำตอบที่ไม่ถูกต้อง คุณสงสัยว่าปัญหาเกิดจากตัวแปร interest_rate ที่รับค่าลบซึ่งไม่ควรเกิดขึ้น เพื่อตรวจสอบสิ่งนี้วางคำสั่ง
ยืนยัน (interest_rate> = 0); ที่สถานที่ในโปรแกรมที่ใช้ interest_rate หากตัวแปรกลายเป็นลบมาโคร assert () จะเตือนคุณ จากนั้นคุณสามารถตรวจสอบรหัสที่เกี่ยวข้องเพื่อค้นหาสาเหตุของปัญหา
เพื่อดูวิธีการยืนยัน () ทำงานเรียกใช้โปรแกรมตัวอย่างด้านล่าง หากคุณป้อนค่าที่ไม่ใช่ศูนย์โปรแกรมจะแสดงค่าและยกเลิกตามปกติ หากคุณป้อนศูนย์แมโครยืนยัน () จะบังคับให้ยุติโปรแกรมที่ผิดปกติ ข้อความแสดงข้อผิดพลาดที่แน่นอนที่คุณเห็นจะขึ้นอยู่กับคอมไพเลอร์ของคุณ แต่นี่เป็นตัวอย่างทั่วไป:
การยืนยันล้มเหลว: x, รายการไฟล์ 19_3.c, บรรทัดที่ 13 โปรดทราบว่าเพื่อให้ assert () ทำงานได้โปรแกรมของคุณจะต้องรวบรวมในโหมดการแก้ไขข้อบกพร่อง อ้างถึงเอกสารประกอบคอมไพเลอร์ของคุณสำหรับข้อมูลเกี่ยวกับการเปิดใช้งานโหมดดีบัก (ดังอธิบายในชั่วขณะ) เมื่อคุณคอมไพล์รุ่นสุดท้ายในโหมดนำออกใช้แมโคร assert () จะถูกปิดใช้งาน
int x;
printf("\nEnter an integer value: ");
scanf("%d", &x);
assert(x >= 0);
printf("You entered %d.\n", x);
return(0);
ป้อนค่าจำนวนเต็ม: 10
คุณป้อน 10
ป้อนค่าจำนวนเต็ม: -1
ข้อความแสดงข้อผิดพลาด: การยกเลิกโปรแกรมผิดปกติ
ข้อความแสดงข้อผิดพลาดของคุณอาจแตกต่างกันขึ้นอยู่กับระบบและคอมไพเลอร์ของคุณ แต่แนวคิดทั่วไปเหมือนกัน
สิ่งที่ต้องการ 'ยกข้อยกเว้น' และ 'หยุดการทำงาน' อาจเป็นจริงสำหรับคอมไพเลอร์ส่วนใหญ่ แต่ไม่ใช่สำหรับทุกคน (BTW มีข้อความยืนยันที่ทำให้เกิดข้อยกเว้นจริง ๆ หรือไม่?)
นี่คือความหมายที่น่าสนใจและแตกต่างกันเล็กน้อยของการยืนยันที่ใช้โดย c6x และคอมไพเลอร์ TI อื่น ๆ : เมื่อเห็นข้อความยืนยันที่แน่นอนคอมไพเลอร์เหล่านี้จะใช้ข้อมูลในคำสั่งนั้นเพื่อทำการปรับให้เหมาะสม ชั่วร้าย
ตัวอย่างใน C:
int dot_product(short *x, short *y, short z)
{
int sum = 0
int i;
assert( ( (int)(x) & 0x3 ) == 0 );
assert( ( (int)(y) & 0x3 ) == 0 );
for( i = 0 ; i < z ; ++i )
sum += x[ i ] * y[ i ];
return sum;
}
สิ่งนี้บอกให้คอมไพเลอร์อาร์เรย์ถูกจัดตำแหน่งบนขอบเขต 32- บิตดังนั้นคอมไพเลอร์สามารถสร้างคำสั่งเฉพาะสำหรับการจัดแนวแบบนั้นได้
ร่างมาตรฐาน C ++ 11 N3337
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
19.3 การยืนยัน
1 ส่วนหัว <cassert> ซึ่งอธิบายไว้ใน (ตารางที่ 42) จัดเตรียมแมโครสำหรับการทำเอกสารการยืนยันโปรแกรม C ++ และกลไกสำหรับปิดการใช้งานการตรวจสอบการยืนยัน
2 เนื้อหาเหมือนกันกับส่วนหัวของไลบรารีมาตรฐาน C <assert.h>
ร่างมาตรฐาน C99 N1256
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
7.2 การวินิจฉัย <assert.h>
1 ส่วนหัว
<assert.h>
กำหนดแมโครยืนยันและหมายถึงแมโครอื่นซึ่งไม่ได้ถูกกำหนดโดยNDEBUG
<assert.h>
หากNDEBUG
ถูกกำหนดให้เป็นชื่อแมโครที่จุดในไฟล์ต้นฉบับที่มี <assert.h> รวมอยู่แมโคร assert จะถูกกำหนดอย่างง่าย ๆ ดังนี้#define assert(ignore) ((void)0)
แมโครยืนยันจะถูกกำหนดใหม่ตามสถานะปัจจุบันของ NDEBUG ทุกครั้งที่
<assert.h>
รวม2. แมโครยืนยันจะต้องถูกนำมาใช้เป็นแมโครไม่ใช่ฟังก์ชันจริง หากคำจำกัดความของแมโครถูกระงับเพื่อให้สามารถเข้าถึงฟังก์ชันที่แท้จริงได้พฤติกรรมนั้นจะไม่ได้กำหนดไว้
7.2.1 การวินิจฉัยโปรแกรม
7.2.1.1 แมโครยืนยัน
สรุป
1
#include <assert.h> void assert(scalar expression);
ลักษณะ
2 แมโคร assert ทำการทดสอบวินิจฉัยลงในโปรแกรม มันจะขยายเป็นนิพจน์ที่เป็นโมฆะ เมื่อมีการดำเนินการหากการแสดงออก (ซึ่งจะมีประเภทเซนต์คิตส์และเนวิส) เป็นเท็จ (นั่นคือเปรียบเทียบเท่ากับ 0) แมโครยืนยันยืนยันเขียนข้อมูลเกี่ยวกับการโทรเฉพาะที่ล้มเหลว (รวมถึงข้อความของอาร์กิวเมนต์ชื่อของ แฟ้มแหล่งที่มาจำนวนแหล่งบรรทัดและชื่อของฟังก์ชั่นปิดล้อม - หลังตามลำดับค่าของแมโครการ preprocessing
__FILE__
และ__LINE__
และระบุ__func__
) บนกระแสข้อผิดพลาดมาตรฐานในรูปแบบการดำเนินงานที่กำหนดไว้ 165) จากนั้นเรียกใช้ฟังก์ชันยกเลิกผลตอบแทน
3 แมโครยืนยันไม่คืนค่าใด ๆ
มีสามเหตุผลหลักสำหรับการใช้ฟังก์ชั่น assert () เหนือปกติถ้าอื่นและ printf
ฟังก์ชั่น assert () ส่วนใหญ่จะใช้ในขั้นตอนการตรวจแก้จุดบกพร่องมันน่าเบื่อที่จะเขียนถ้ามีคำสั่ง printf ทุกครั้งที่คุณต้องการทดสอบเงื่อนไขที่อาจไม่ได้ทำในรหัสสุดท้าย
ในการปรับใช้ซอฟต์แวร์ขนาดใหญ่ assert มีประโยชน์อย่างมากในการที่คุณสามารถทำให้คอมไพเลอร์เพิกเฉยต่อคำสั่ง assert โดยใช้มาโคร NDEBUG ที่กำหนดไว้ก่อนที่จะลิงก์ไฟล์ส่วนหัวสำหรับฟังก์ชั่น assert ()
assert () มีประโยชน์เมื่อคุณกำลังออกแบบฟังก์ชั่นหรือโค้ดบางอย่างและต้องการที่จะรับความคิดเกี่ยวกับสิ่งที่ จำกัด รหัสที่จะและไม่ทำงาน
มันเป็นฟังก์ชั่นที่จะหยุดการทำงานของโปรแกรมหากค่าที่ประเมินไว้เป็นเท็จ โดยปกติจะล้อมรอบด้วยแมโครเพื่อไม่ให้คอมไพล์ลงในไบนารีผลลัพธ์เมื่อคอมไพล์ด้วยการตั้งค่ารีลีส
มันถูกออกแบบมาเพื่อใช้ในการทดสอบสมมติฐานที่คุณทำ ตัวอย่างเช่น:
void strcpy(char* dest, char* src){
//pointers shouldn't be null
assert(dest!=null);
assert(src!=null);
//copy string
while(*dest++ = *src++);
}
อุดมคติที่คุณต้องการคือคุณสามารถทำให้เกิดข้อผิดพลาดในโปรแกรมของคุณเช่นการเรียกฟังก์ชันที่มีอาร์กิวเมนต์ที่ไม่ถูกต้องและคุณกดยืนยันก่อนที่จะ segfaults (หรือล้มเหลวในการทำงานตามที่คาดไว้)
นอกจากนี้คุณสามารถใช้เพื่อตรวจสอบว่าการจัดสรรแบบไดนามิกสำเร็จหรือไม่
ตัวอย่างรหัส:
int ** p;
p = new int * [5]; // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
// array (size 3) of actual int values
}
assert (p); // Check the dynamic allocation.
คล้ายกับ:
if (p == NULL) {
cout << "dynamic allocation failed" << endl;
exit(1);
}
new
ส่งข้อยกเว้นเกี่ยวกับการจัดสรรล้มเหลวเว้นแต่คุณจะระบุnothrow
(ซึ่งคุณไม่ได้อยู่ที่นี่) นอกจากนี้การจัดรูปแบบของคุณแปลกและexit
ชั่วร้าย
assert()
เป็นเพียงการแก้จุดบกพร่องและปั๊มออกสิ่งที่ไม่ควรเคยไม่เคยเกิดขึ้น - นานก่อนที่จะปล่อยสร้างทำ