亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

探討C語言的那些小秘密之斷言

2020-01-26 15:50:20
字體:
來源:轉載
供稿:網友

每次寫摘要我都覺得是一件很頭疼的事兒,因為我知道摘要真的很重要,它幾乎直接就決定了讀者的數量??赡芑司帕⒅懗鰜淼臇|西,因為摘要的失敗而前功盡棄,因為絕大多數的讀者看文章之前都會瀏覽下摘要,如果他們發現摘要“不對口”,沒有什么特色和吸引人的地方,那么輕則采用一目十行的方法看完全文,重則對文章判“死刑”,一篇文章的好壞雖然不能用摘要來衡量,但是它卻常常被讀者用來衡量一篇文章的好壞,從而成為了文章讀者數量多少的一個關鍵因素。下面言歸正傳來說說斷言,如果出于一般性的學習C語言,應付考試的話,我想很少有人會在代碼中使用斷言,可能有的人在此之前從來沒有使用過斷言。那么斷言的使用到底能給我們的代碼帶來什么呢?我盡可能的把我所理解的斷言的使用講解清楚,希望我在此所講的斷言能夠對你有所幫助,讓你以后能夠在代碼中靈活使用斷言。

在講解之前,我們先來對斷言做一個基本的介紹,讓大家對斷言有一個大致的了解。在使用C語言編寫工程代碼時,我們總會對某種假設條件進行檢查,斷言就是用于在代碼中捕捉這些假設,可以將斷言看作是異常處理的一種高級形式。斷言表示為一些布爾表達式,程序員相信在程序中的某個特定點該表達式值為真??梢栽谌魏螘r候啟用和禁用斷言驗證,因此可以在測試時啟用斷言,而在部署時禁用斷言。同樣,程序投入運行后,最終用戶在遇到問題時可以重新起用斷言。它可以快速發現并定位軟件問題,同時對系統錯誤進行自動報警。斷言可以對在系統中隱藏很深,用其它手段極難發現的問題可以用斷言來進行定位,從而縮短軟件問題定位時間,提高系統的可測性。實際應用時,可根據具體情況靈活地設計斷言。

通過上面的講解我們對于斷言算是有了一個大概的了解,那么接下來我們就來看看C語言中assert宏在代碼中的使用。

原型定義:
void assert( int expression );

assert宏的原型定義在<assert.h>中,其作用是先計算表達式 expression ,如果expression的值為假(即為0),那么它先向stderr打印一條出錯信息,然后通過調用abort 來終止程序運行。

下面來看看一段代碼:

復制代碼 代碼如下:

#include <stdio.h>
#include <assert.h>

int main( void )
{
      int i;
   i=1;
   assert(i++);


   printf("%d/n",i);

       return 0;
}


運行結果為:

看看運行結果,因為我們給定的i初始值為1,所以使用assert(i++);語句的時候不會出現錯誤,進而執行了i++,所以其后的打印語句輸出值為2。如果我們把i的初始值改為0,那么就回出現如下錯誤。
Assertion failed: i++, file E:/fdsa/assert2.cpp, line 8
Press any key to continue

是不是發現根據提示很快就能定位出錯點呢?!既然assert這么便于定位出錯點,看來的確我們有必要熟練的在代碼中使用它,但是什么東西的使用都是有規則的,assert的使用也不例外。

斷言語句不是永遠會執行,可以屏蔽也可以啟用,這就要求assert不管是在屏蔽還是啟用的情況下都不能對我們本身代碼的功能有所影響,這樣的話剛才我們在代碼中使用了一句assert(i++);是不妥的,因為我們一旦禁用了assert,i++的語句就得不到執行,對于接下來i值的使用就會出現問題了,所以對于這樣的語句我們應該是要分開來實現,寫出如下兩句來替代, assert(i); i++;,所以這就對于斷言的使用有了相應的要求,那么我們一般在什么情況下使用斷言呢?主要體現在一下幾個方面:

1.可以在預計正常情況下程序不會到達的地方放置斷言。(如assert (0);)

2.使用斷言測試方法執行的前置條件和后置條件 。

3.使用斷言檢查類的不變狀態,確保任何情況下,某個變量的狀態必須滿足。(如某個變量的變化范圍)

對于上面的前置條件和后置條件可能有的讀者還不是很了解,那么看看下面的解釋你就明白了。

前置條件斷言:代碼執行之前必須具備的特性

后置條件斷言:代碼執行之后必須具備的特性

前后不變斷言:代碼執行前后不能變化的特性

當然在使用的斷言的過程中會有一些我們應該注意的事項和養成一些良好的習慣,如:

1.每個assert只檢驗一個條件,因為同時檢驗多個條件時,如果斷言失敗,我們就無法直觀的判斷是哪個條件失敗

2.不能使用改變環境的語句,就像我們上面的代碼改變了i變量,在實際編寫代碼的過程中是不能這樣做的

3.assert和后面的語句應空一行,以形成邏輯和視覺上的一致感,也算是一種良好的編程習慣吧,讓編寫的代碼有一種視覺上的美感

4.有的地方,assert不能代替條件過濾

5.放在函數參數的入口處檢查傳入參數的合法性

6.斷言語句不可以有任何邊界效應

上面那么多的文字,似乎很枯燥,但是沒辦法,我們不能急功近利,還是要先堅持看完文字描述部分,這樣在下面我們分析代碼的過程中就能很快知道為什么會出現那樣的問題了,也能在自己編寫代碼的時候熟練的使用assert,給自己的代碼調試帶來極大的便利,尤其是你在用C語言做工程項目的時候,如果你能夠在你的代碼中合理的使用assert,能使你創建更穩定、質量更好且不易于出錯的代碼。當需要在一個值為FALSE時中斷當前操作的話,可以使用斷言。單元測試必須使用斷言,除了類型檢查和單元測試外,斷言還提供了一種確定各種特性是否在程序中得到維護的極好的方法。但凡優秀的程序員都能夠在自己代碼中很好的使用assert,編寫出高質量的代碼來。

說了assert這么多的有點,當然也要說說它的缺點了。

使用assert的缺點是,頻繁的調用會極大的影響程序的性能,增加額外的開銷。所以在調試結束后,可以通過在包含#include 的語句之前插入 #define NDEBUG 來禁用assert調用。

接下面分析一下下面的一段代碼:

復制代碼 代碼如下:

#include <stdio.h>
//#define NDEBUG
#include <assert.h>

int copy_string(char from[],char to[])
{
 int i=0;
 while(to[i++]=from[i]);

 printf("%s/n",to);

 return 1;
}

int main()
{
 char str[]="this is a string!";
 char dec_str[206];

 printf("%s/n",str);

 assert(copy_string(str,dec_str));

 printf("%s/n",dec_str);

 return 0;
}


運行結果為:

在以上代碼的開頭部分我們把#define NDEBUG給注釋掉了,所以我們啟用了assert,main函數中使用了assert(copy_string(str,dec_str));來實現copy_string函數的調用,在copy_string函數中我們使用了一句return 1,所以最終的函數調用結果就等價于是assert(1),所以接下來繼續執行assert下面的打印語句,最終成功的打印了三條輸出語句,如果我們把開頭的注釋部分打開,結果就只能成功的輸出起始部分一條打印語句。

以上我們都是在圍繞著assert宏在講解,僅僅是教會大家如何來使用assert宏,那么接下來看看我們如何來實現自己的斷言呢?

接下來我們看看另外一段代碼:

復制代碼 代碼如下:

#include <stdio.h>

//#undef  _EXAM_ASSERT_TEST_    //禁用
#define  _EXAM_ASSERT_TEST_   //啟用
#ifdef _EXAM_ASSERT_TEST_     //啟用斷言測試
 void assert_report( const char * file_name, const char * function_name, unsigned int line_no )
{
 printf( "/n[EXAM]Error Report file_name: %s, function_name: %s, line %u/n",
         file_name, function_name, line_no );

}
 #define  ASSERT_REPORT( condition )       /
 do{       /
 if ( condition )       /
  NULL;        /
 else         /
  assert_report( __FILE__, __func__, __LINE__ ); /
 }while(0)
 #else // 禁用斷言測試
#define ASSERT_REPORT( condition )  NULL
#endif /* end of ASSERT */
 int main( void )
{
    int i;
    i=0;
   // assert(i++);
   ASSERT_REPORT(i);
     printf("%d/n",i);
        return 0;
}


運行結果如下:

[EXAM]Error Report file_name: assert3.c, function_name: main, line 29
0
細心的讀者會發現我們并沒有使用斷言來結束當前程序的執行,所以在斷言下面的printf成功的打印出了i的當前值,當然我們也可以做適當的修改,在斷言出發現錯誤,那么就調用 abort();來使當前正在執行的程序異常終止,修改如下:

復制代碼 代碼如下:

#include <stdio.h>
#include <stdlib.h>

//#undef  _EXAM_ASSERT_TEST_    //禁用
#define  _EXAM_ASSERT_TEST_   //啟用
#ifdef _EXAM_ASSERT_TEST_     //啟用斷言測試
 void assert_report( const char * file_name, const char * function_name, unsigned int line_no )
{
 printf( "/n[EXAM]Error Report file_name: %s, function_name: %s, line %u/n",
         file_name, function_name, line_no );
  abort();
}

#define  ASSERT_REPORT( condition )       /
 do{       /
 if ( condition )       /
  NULL;        /
 else         /
  assert_report( __FILE__, __func__, __LINE__ ); /
 }while(0)

#else // 禁用斷言測試
#define ASSERT_REPORT( condition )  NULL
#endif /* end of ASSERT */
 int main( void )
{
    int i;
    i=0;
   // assert(i++);
   ASSERT_REPORT(i);
    printf("%d/n",i);
    return 0;

}


運行結果如下:

[EXAM]Error Report file_name: assert3.c, function_name: main, line 31
Aborted
此時就不會在執行接下來的打印語句了。看看我們自己的實現方式就知道,我們自己編寫的斷言可以比直接調用assert宏可以得到更多的信息量,主要是由于我們自己編寫的斷言更加的具有靈活性,可以根據自己的需要來打印輸出不同的信息,同時也可以對于不同類型的錯誤或者警告信息使用不同的斷言,這也是在工程代碼中經常使用的做法。如果你在關注代碼運行結果的同時也認真的閱讀了我的代碼,你會發現其中我在宏定義中使用了一個do{}while(0),使用它有什么好處呢,或許在以上的代碼中并沒有體現出來,那么我們看看下面的代碼你就知道了。

復制代碼 代碼如下:

#include <stdio.h>

void print_1(void)
{
 printf("print_1/n");
}
void print_2(void)
{
 printf("print_2/n");
}
#define  printf_value()    /
   print_1();   /
   print_2();   /

int main( void )
{
 int i=0;
 if(i==1)
 printf_value();

 return 0;
}


運行結果:

還是備份一下文章描述,以防圖片打開失敗給讀者帶來困擾。

print_2
Press any key to continue

看了上面運行結果可能有的讀者會很疑惑為什么會出現以上的錯誤呢?!if語句的條件不滿足,那么print_value()函數應該不會被調用啊,怎么會打印呢。如果我們把上面的printf_value()替換為 print_1();  print_2();,就會很清楚的發現if語句在此的作用僅僅是不調用print_1();,而print_2();在控制之外,所以出現了上面的結果,有的讀者可能會馬上想到我們加上一個{}不就好了嗎,在這里的確是加一個{}就可以了,因為這里是一個特殊情況,沒有else語句,如果我們在以上的宏定義中使用{},加入else語句后再來看看代碼。

復制代碼 代碼如下:

#include <stdio.h>

void print_1(void)
{
 printf("print_1/n");
}

void print_2(void)
{
 printf("print_2/n");
}

#define  printf_value()    /
  {     /
  print_1();   /
  print_2();}


int main( void )
{
 int i=0;
 if(i==1)
  printf_value();
 else
  printf("add else word!!!");

 return 0;
}


看似正確的代碼,我們編譯就會出現如下錯誤:

error C2181: illegal else without matching if

為什么會出現這樣的錯誤呢?因為我們編寫C語言代碼時,在每個語句后面加分號是一種約定俗成的習慣,以上代碼中我們在printf_value()語句后面加了一個分號,正是由于這個分號的作用使得else沒有與之相對應的if,所以編譯出錯。但是如果我們使用do{}while(0)就不會出現這些問題,所以我們在編寫代碼的時候應該學會在宏定義中使用do{}while(0)。

C語言斷言內容的講解到此就該結束了,上面內容已給出了在C語言編寫代碼的過程中斷言較為詳細的使用,其中后面使用我們自己實現的斷言算得上是一個比較經典的斷言設計方法了,讀者可以在自己以后編寫C語言代碼的過程中參考下。由于本人水平有限,文章中的不妥或錯誤之處在所難免,殷切希望讀者批評指正。同時也歡迎讀者共同探討相關的內容,如果樂意交流的話請留下你寶貴的意見。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩欧美在线视频| 国产日韩一区在线| 中文在线不卡视频| 亲爱的老师9免费观看全集电视剧| 日韩专区在线观看| 欧美专区国产专区| 精品性高朝久久久久久久| 欧美成人在线免费视频| 日韩中文字幕在线| 亚洲精品久久久久久久久久久| 国产亚洲精品91在线| 日韩女在线观看| 高清一区二区三区日本久| 欧美色欧美亚洲高清在线视频| 亚洲国产精品推荐| 国产成人精品在线观看| 欧美在线视频在线播放完整版免费观看| 日韩av黄色在线观看| 久久免费精品日本久久中文字幕| 国产精品视频在线播放| 欧美午夜视频在线观看| 久久在线观看视频| 91热福利电影| 欧美一区二区三区免费视| 精品久久久久久中文字幕大豆网| 久久国产加勒比精品无码| 亚洲欧美激情在线视频| 中文字幕亚洲自拍| 国产精品视频一区二区三区四| 欧美精品一二区| 亚洲成人黄色在线观看| 伊人男人综合视频网| 国产高清视频一区三区| 国产精品揄拍一区二区| 国产手机视频精品| 91精品视频在线免费观看| 久久久国产一区| 欧美日韩成人免费| 国产美女扒开尿口久久久| 国产盗摄xxxx视频xxx69| 久久久999成人| 欧美成人自拍视频| 色综合天天综合网国产成人网| 爱福利视频一区| 免费91在线视频| 国产欧美精品va在线观看| 亚洲免费人成在线视频观看| 日韩极品精品视频免费观看| 精品国偷自产在线视频| 色综合天天综合网国产成人网| 91久久精品国产| 日韩美女激情视频| 青青a在线精品免费观看| 日韩国产激情在线| 免费不卡欧美自拍视频| 亚洲精品中文字| 国产91露脸中文字幕在线| 国产精品私拍pans大尺度在线| 国产美女久久久| 欧美成人精品在线播放| 欧美黑人巨大精品一区二区| 欧美中文字幕视频在线观看| 国产精品人成电影| 97香蕉久久夜色精品国产| 91在线视频成人| 最近免费中文字幕视频2019| 国产91ⅴ在线精品免费观看| 国产成人精品网站| 亚洲区一区二区| 欧美麻豆久久久久久中文| 欧美另类老女人| 97超视频免费观看| 九九热精品视频国产| 92看片淫黄大片看国产片| 久久国产精品免费视频| 国语自产精品视频在免费| 欧美丰满老妇厨房牲生活| 日韩精品视频免费专区在线播放| 色爱精品视频一区| 亚洲欧美中文字幕| 日本久久亚洲电影| 国产日韩在线看| 国产欧美在线视频| 最近2019中文字幕第三页视频| 色婷婷av一区二区三区在线观看| 久久久久99精品久久久久| 一区二区三区美女xx视频| 97色伦亚洲国产| 97久久超碰福利国产精品…| 欧美日韩日本国产| 欧美巨猛xxxx猛交黑人97人| 国产亚洲精品va在线观看| 91久久精品国产| 国产亚洲免费的视频看| 久久琪琪电影院| 国产成人在线亚洲欧美| 日本高清+成人网在线观看| 日韩中文字幕网站| 精品久久香蕉国产线看观看gif| 日本高清不卡的在线| 久久亚洲春色中文字幕| 国产91|九色| 亚洲精品在线不卡| 91国产美女在线观看| 亚洲精品一区中文| 国产精品mp4| 精品综合久久久久久97| www.亚洲免费视频| 久久久免费观看视频| 欧美亚洲午夜视频在线观看| 欧美亚洲国产另类| 一区三区二区视频| 国产精品白嫩美女在线观看| 久久国产加勒比精品无码| 欧美乱妇40p| 久久99视频精品| www.日韩免费| 国产精品海角社区在线观看| www.久久草.com| 国产精品羞羞答答| 55夜色66夜色国产精品视频| 一本大道亚洲视频| 成人在线观看视频网站| 日韩精品久久久久久福利| 日韩视频免费在线观看| 5252色成人免费视频| 亚洲欧美日韩精品久久| 久久久99免费视频| 久久久影视精品| 久久99热精品这里久久精品| 中文国产成人精品久久一| 国产精品一区二区三区免费视频| 亚洲а∨天堂久久精品9966| 久久久久久久久久久国产| 在线观看日韩专区| 亚洲伊人久久大香线蕉av| 亲爱的老师9免费观看全集电视剧| 亚洲qvod图片区电影| 中文字幕亚洲欧美一区二区三区| 亚洲精品一区中文字幕乱码| 欧洲成人免费视频| 欧美激情亚洲激情| 欧美重口另类videos人妖| 亚洲国产精品久久久久久| 中日韩美女免费视频网址在线观看| 亚洲国产高清福利视频| 久久成人精品一区二区三区| 日韩av在线一区二区| 精品国产乱码久久久久久虫虫漫画| 久久久久亚洲精品成人网小说| 一级做a爰片久久毛片美女图片| 欧美国产日韩一区二区在线观看| 欧美成人小视频| 久久久久久国产精品| 久久国产一区二区三区| 日韩久久精品电影| 国外日韩电影在线观看| 亚洲精品一区二区在线| 亚洲欧美成人一区二区在线电影| 久久午夜a级毛片| 欧美老肥婆性猛交视频| 午夜精品久久久久久久久久久久久| 日韩av有码在线| 日韩成人在线视频网站|