最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

探討C語(yǔ)言的那些小秘密之?dāng)嘌?/h1>
 更新時(shí)間:2013年09月23日 09:15:49   作者:  
我盡可能的把我所理解的斷言的使用講解清楚,希望我在此所講的斷言能夠?qū)δ阌兴鶐椭?,讓你以后能夠在代碼中靈活使用斷言

每次寫(xiě)摘要我都覺(jué)得是一件很頭疼的事兒,因?yàn)槲抑勒娴暮苤匾?,它幾乎直接就決定了讀者的數(shù)量??赡芑司帕⒅?xiě)出來(lái)的東西,因?yàn)檎氖《肮ΡM棄,因?yàn)榻^大多數(shù)的讀者看文章之前都會(huì)瀏覽下摘要,如果他們發(fā)現(xiàn)摘要“不對(duì)口”,沒(méi)有什么特色和吸引人的地方,那么輕則采用一目十行的方法看完全文,重則對(duì)文章判“死刑”,一篇文章的好壞雖然不能用摘要來(lái)衡量,但是它卻常常被讀者用來(lái)衡量一篇文章的好壞,從而成為了文章讀者數(shù)量多少的一個(gè)關(guān)鍵因素。下面言歸正傳來(lái)說(shuō)說(shuō)斷言,如果出于一般性的學(xué)習(xí)C語(yǔ)言,應(yīng)付考試的話,我想很少有人會(huì)在代碼中使用斷言,可能有的人在此之前從來(lái)沒(méi)有使用過(guò)斷言。那么斷言的使用到底能給我們的代碼帶來(lái)什么呢?我盡可能的把我所理解的斷言的使用講解清楚,希望我在此所講的斷言能夠?qū)δ阌兴鶐椭?,讓你以后能夠在代碼中靈活使用斷言。

在講解之前,我們先來(lái)對(duì)斷言做一個(gè)基本的介紹,讓大家對(duì)斷言有一個(gè)大致的了解。在使用C語(yǔ)言編寫(xiě)工程代碼時(shí),我們總會(huì)對(duì)某種假設(shè)條件進(jìn)行檢查,斷言就是用于在代碼中捕捉這些假設(shè),可以將斷言看作是異常處理的一種高級(jí)形式。斷言表示為一些布爾表達(dá)式,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真。可以在任何時(shí)候啟用和禁用斷言驗(yàn)證,因此可以在測(cè)試時(shí)啟用斷言,而在部署時(shí)禁用斷言。同樣,程序投入運(yùn)行后,最終用戶在遇到問(wèn)題時(shí)可以重新起用斷言。它可以快速發(fā)現(xiàn)并定位軟件問(wèn)題,同時(shí)對(duì)系統(tǒng)錯(cuò)誤進(jìn)行自動(dòng)報(bào)警。斷言可以對(duì)在系統(tǒng)中隱藏很深,用其它手段極難發(fā)現(xiàn)的問(wèn)題可以用斷言來(lái)進(jìn)行定位,從而縮短軟件問(wèn)題定位時(shí)間,提高系統(tǒng)的可測(cè)性。實(shí)際應(yīng)用時(shí),可根據(jù)具體情況靈活地設(shè)計(jì)斷言。

通過(guò)上面的講解我們對(duì)于斷言算是有了一個(gè)大概的了解,那么接下來(lái)我們就來(lái)看看C語(yǔ)言中assert宏在代碼中的使用。

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

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

下面來(lái)看看一段代碼:

復(fù)制代碼 代碼如下:

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

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


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

       return 0;
}


運(yùn)行結(jié)果為:

看看運(yùn)行結(jié)果,因?yàn)槲覀兘o定的i初始值為1,所以使用assert(i++);語(yǔ)句的時(shí)候不會(huì)出現(xiàn)錯(cuò)誤,進(jìn)而執(zhí)行了i++,所以其后的打印語(yǔ)句輸出值為2。如果我們把i的初始值改為0,那么就回出現(xiàn)如下錯(cuò)誤。
Assertion failed: i++, file E:\fdsa\assert2.cpp, line 8
Press any key to continue

是不是發(fā)現(xiàn)根據(jù)提示很快就能定位出錯(cuò)點(diǎn)呢?!既然assert這么便于定位出錯(cuò)點(diǎn),看來(lái)的確我們有必要熟練的在代碼中使用它,但是什么東西的使用都是有規(guī)則的,assert的使用也不例外。

斷言語(yǔ)句不是永遠(yuǎn)會(huì)執(zhí)行,可以屏蔽也可以啟用,這就要求assert不管是在屏蔽還是啟用的情況下都不能對(duì)我們本身代碼的功能有所影響,這樣的話剛才我們?cè)诖a中使用了一句assert(i++);是不妥的,因?yàn)槲覀円坏┙昧薬ssert,i++的語(yǔ)句就得不到執(zhí)行,對(duì)于接下來(lái)i值的使用就會(huì)出現(xiàn)問(wèn)題了,所以對(duì)于這樣的語(yǔ)句我們應(yīng)該是要分開(kāi)來(lái)實(shí)現(xiàn),寫(xiě)出如下兩句來(lái)替代, assert(i); i++;,所以這就對(duì)于斷言的使用有了相應(yīng)的要求,那么我們一般在什么情況下使用斷言呢?主要體現(xiàn)在一下幾個(gè)方面:

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

2.使用斷言測(cè)試方法執(zhí)行的前置條件和后置條件 。

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

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

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

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

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

當(dāng)然在使用的斷言的過(guò)程中會(huì)有一些我們應(yīng)該注意的事項(xiàng)和養(yǎng)成一些良好的習(xí)慣,如:

1.每個(gè)assert只檢驗(yàn)一個(gè)條件,因?yàn)橥瑫r(shí)檢驗(yàn)多個(gè)條件時(shí),如果斷言失敗,我們就無(wú)法直觀的判斷是哪個(gè)條件失敗

2.不能使用改變環(huán)境的語(yǔ)句,就像我們上面的代碼改變了i變量,在實(shí)際編寫(xiě)代碼的過(guò)程中是不能這樣做的

3.assert和后面的語(yǔ)句應(yīng)空一行,以形成邏輯和視覺(jué)上的一致感,也算是一種良好的編程習(xí)慣吧,讓編寫(xiě)的代碼有一種視覺(jué)上的美感

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

5.放在函數(shù)參數(shù)的入口處檢查傳入?yún)?shù)的合法性

6.斷言語(yǔ)句不可以有任何邊界效應(yīng)

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

說(shuō)了assert這么多的有點(diǎn),當(dāng)然也要說(shuō)說(shuō)它的缺點(diǎn)了。

使用assert的缺點(diǎn)是,頻繁的調(diào)用會(huì)極大的影響程序的性能,增加額外的開(kāi)銷。所以在調(diào)試結(jié)束后,可以通過(guò)在包含#include 的語(yǔ)句之前插入 #define NDEBUG 來(lái)禁用assert調(diào)用。

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

復(fù)制代碼 代碼如下:

#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;
}


運(yùn)行結(jié)果為:

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

以上我們都是在圍繞著assert宏在講解,僅僅是教會(huì)大家如何來(lái)使用assert宏,那么接下來(lái)看看我們?nèi)绾蝸?lái)實(shí)現(xiàn)自己的斷言呢?

接下來(lái)我們看看另外一段代碼:

復(fù)制代碼 代碼如下:

#include <stdio.h>

//#undef  _EXAM_ASSERT_TEST_    //禁用
#define  _EXAM_ASSERT_TEST_   //啟用
#ifdef _EXAM_ASSERT_TEST_     //啟用斷言測(cè)試
 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 // 禁用斷言測(cè)試
#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;
}


運(yùn)行結(jié)果如下:

[EXAM]Error Report file_name: assert3.c, function_name: main, line 29
0
細(xì)心的讀者會(huì)發(fā)現(xiàn)我們并沒(méi)有使用斷言來(lái)結(jié)束當(dāng)前程序的執(zhí)行,所以在斷言下面的printf成功的打印出了i的當(dāng)前值,當(dāng)然我們也可以做適當(dāng)?shù)男薷?,在斷言出發(fā)現(xiàn)錯(cuò)誤,那么就調(diào)用 abort();來(lái)使當(dāng)前正在執(zhí)行的程序異常終止,修改如下:

復(fù)制代碼 代碼如下:

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

//#undef  _EXAM_ASSERT_TEST_    //禁用
#define  _EXAM_ASSERT_TEST_   //啟用
#ifdef _EXAM_ASSERT_TEST_     //啟用斷言測(cè)試
 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 // 禁用斷言測(cè)試
#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;

}


運(yùn)行結(jié)果如下:

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

復(fù)制代碼 代碼如下:

#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;
}


運(yùn)行結(jié)果:

還是備份一下文章描述,以防圖片打開(kāi)失敗給讀者帶來(lái)困擾。

print_2
Press any key to continue

看了上面運(yùn)行結(jié)果可能有的讀者會(huì)很疑惑為什么會(huì)出現(xiàn)以上的錯(cuò)誤呢?!if語(yǔ)句的條件不滿足,那么print_value()函數(shù)應(yīng)該不會(huì)被調(diào)用啊,怎么會(huì)打印呢。如果我們把上面的printf_value()替換為 print_1();  print_2();,就會(huì)很清楚的發(fā)現(xiàn)if語(yǔ)句在此的作用僅僅是不調(diào)用print_1();,而print_2();在控制之外,所以出現(xiàn)了上面的結(jié)果,有的讀者可能會(huì)馬上想到我們加上一個(gè){}不就好了嗎,在這里的確是加一個(gè){}就可以了,因?yàn)檫@里是一個(gè)特殊情況,沒(méi)有else語(yǔ)句,如果我們?cè)谝陨系暮甓x中使用{},加入else語(yǔ)句后再來(lái)看看代碼。

復(fù)制代碼 代碼如下:

#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;
}


看似正確的代碼,我們編譯就會(huì)出現(xiàn)如下錯(cuò)誤:

error C2181: illegal else without matching if

為什么會(huì)出現(xiàn)這樣的錯(cuò)誤呢?因?yàn)槲覀兙帉?xiě)C語(yǔ)言代碼時(shí),在每個(gè)語(yǔ)句后面加分號(hào)是一種約定俗成的習(xí)慣,以上代碼中我們?cè)趐rintf_value()語(yǔ)句后面加了一個(gè)分號(hào),正是由于這個(gè)分號(hào)的作用使得else沒(méi)有與之相對(duì)應(yīng)的if,所以編譯出錯(cuò)。但是如果我們使用do{}while(0)就不會(huì)出現(xiàn)這些問(wèn)題,所以我們?cè)诰帉?xiě)代碼的時(shí)候應(yīng)該學(xué)會(huì)在宏定義中使用do{}while(0)。

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

相關(guān)文章

  • C++的std::transform()的實(shí)現(xiàn)

    C++的std::transform()的實(shí)現(xiàn)

    在 C++ 標(biāo)準(zhǔn)庫(kù)中,std::transform() 是一個(gè)非常有用的算法函數(shù),它能夠?qū)⒔o定范圍中的每個(gè)元素進(jìn)行變換,并將變換后的結(jié)果存儲(chǔ)到另一個(gè)范圍中,本文就詳細(xì)的介紹一下具體用法,感興趣的可以了解一下
    2023-08-08
  • C++遞歸算法處理島嶼問(wèn)題詳解

    C++遞歸算法處理島嶼問(wèn)題詳解

    這篇文章主要介紹了用遞歸算法解決島嶼問(wèn)題的流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-10-10
  • C++中push_back()函數(shù)的具體使用

    C++中push_back()函數(shù)的具體使用

    本文主要介紹了C++中push_back()函數(shù)的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • C語(yǔ)言實(shí)現(xiàn)的猜拳游戲代碼分享

    C語(yǔ)言實(shí)現(xiàn)的猜拳游戲代碼分享

    本文給大家分享的是一個(gè)C語(yǔ)言實(shí)現(xiàn)的猜拳小游戲,由于本程序簡(jiǎn)單易操作,交互性好,對(duì)用戶沒(méi)什么特別要求。這里推薦給大家
    2016-02-02
  • Qt控件之QLabel用法及技巧

    Qt控件之QLabel用法及技巧

    QLabel是Qt中的一個(gè)控件類,用于顯示文本或圖像的控件類之一,本文主要介紹了Qt控件之QLabel用法及技巧,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 深入解析C++編程中的運(yùn)算符重載

    深入解析C++編程中的運(yùn)算符重載

    這篇文章主要介紹了C++編程中的運(yùn)算符重載,運(yùn)算符重載是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-04-04
  • Qt實(shí)現(xiàn)給窗口繪制陰影的示例代碼

    Qt實(shí)現(xiàn)給窗口繪制陰影的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)給窗口繪制陰影的方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Qt有一定的幫助,感興趣的可以了解一下
    2022-11-11
  • C語(yǔ)言修煉之路數(shù)據(jù)類型悟正法 解析存儲(chǔ)定風(fēng)魔下篇

    C語(yǔ)言修煉之路數(shù)據(jù)類型悟正法 解析存儲(chǔ)定風(fēng)魔下篇

    使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么
    2022-02-02
  • C++類的大小介紹

    C++類的大小介紹

    這篇文章主要介紹了C++類的大小,在C++中,結(jié)構(gòu)體和類的唯一區(qū)別就是結(jié)構(gòu)體和類具有不同的默認(rèn)訪問(wèn)控制屬性,下面一起進(jìn)入文章查看詳細(xì)內(nèi)容
    2021-11-11
  • Qt實(shí)現(xiàn)屏幕底部冒泡效果

    Qt實(shí)現(xiàn)屏幕底部冒泡效果

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)屏幕底部冒泡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08

最新評(píng)論

大同市| 饶阳县| 高雄市| 疏勒县| 白河县| 凉山| 清河县| 泸州市| 营口市| 榕江县| 丰都县| 平南县| 宣威市| 卫辉市| 绥化市| 婺源县| 留坝县| 九台市| 长葛市| 合阳县| 云霄县| 孙吴县| 克山县| 尉氏县| 郯城县| 日喀则市| 尼勒克县| 天镇县| 乐平市| 喀喇| 伊春市| 驻马店市| 得荣县| 淳化县| 道真| 大埔县| 麻栗坡县| 台湾省| 兴宁市| 秦安县| 梁河县|