在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 牛人業(yè)話(huà) > C語(yǔ)言的那些小秘密之?dāng)嘌?/p>

            C語(yǔ)言的那些小秘密之?dāng)嘌?/h1>
            作者: 時(shí)間:2015-04-04 來(lái)源:網(wǎng)絡(luò) 收藏

              每次寫(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í),應(yīng)付考試的話(huà),我想很少有人會(huì)在代碼中使用,可能有的人在此之前從來(lái)沒(méi)有使用過(guò)。那么斷言的使用到底能給我們的代碼帶來(lái)什么呢?我盡可能的把我所理解的斷言的使用講解清楚,希望我在此所講的斷言能夠?qū)δ阌兴鶐椭?,讓你以后能夠在代碼中靈活使用斷言。

            本文引用地址:http://www.biyoush.com/article/272070.htm

              在講解之前,我們先來(lái)對(duì)斷言做一個(gè)基本的介紹,讓大家對(duì)斷言有一個(gè)大致的了解。在使用編寫(xiě)工程代碼時(shí),我們總會(huì)對(duì)某種假設(shè)條件進(jìn)行檢查,斷言就是用于在代碼中捕捉這些假設(shè),可以將斷言看作是異常處理的一種高級(jí)形式。斷言表示為一些布爾表達(dá)式,程序員相信在程序中的某個(gè)特定點(diǎn)該表達(dá)式值為真。可以在任何時(shí)候啟用和禁用斷言驗(yàn)證,因此可以在測(cè)試時(shí)啟用斷言,而在部署時(shí)禁用斷言。同樣,程序投入運(yùn)行后,最終用戶(hù)在遇到問(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)看看中assert宏在代碼中的使用。

              原型定義:

              void assert( int expression );

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

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

              #include

              #include

              int main( void )

              {

              int i;

              i=1;

              assert(i++);

              printf("%dn",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:fdsaassert2.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ì)我們本身代碼的功能有所影響,這樣的話(huà)剛才我們?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.使用斷言檢查類(lèi)的不變狀態(tài),確保任何情況下,某個(gè)變量的狀態(tài)必須滿(mǎn)足。(如某個(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ú)法直觀(guān)的判斷是哪個(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)前操作的話(huà),可以使用斷言。單元測(cè)試必須使用斷言,除了類(lèi)型檢查和單元測(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)銷(xiāo)。所以在調(diào)試結(jié)束后,可以通過(guò)在包含#include 的語(yǔ)句之前插入 #define NDEBUG 來(lái)禁用assert調(diào)用。

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

              #include

              //#define NDEBUG

              #include

              int copy_string(char from[],char to[])

              {

              int i=0;

              while(to[i++]=from[i]);

              printf("%sn",to);

              return 1;

              }

              int main()

              {

              char str[]="this is a string!";

              char dec_str[206];

              printf("%sn",str);

              assert(copy_string(str,dec_str));

              printf("%sn",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)我們看看另外一段代碼:

              #include

              //#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 %un",

              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("%dn",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ù)男薷模跀嘌猿霭l(fā)現(xiàn)錯(cuò)誤,那么就調(diào)用 abort();來(lái)使當(dāng)前正在執(zhí)行的程序異常終止,修改如下:

              #include

              #include

              //#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 %un",

              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("%dn",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ì)于不同類(lèi)型的錯(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),那么我們看看下面的代碼你就知道了。

              #include

              void print_1(void)

              {

              printf("print_1n");

              }

              void print_2(void)

              {

              printf("print_2n");

              }

              #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ǔ)句的條件不滿(mǎn)足,那么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)看看代碼。

              #include

              void print_1(void)

              {

              printf("print_1n");

              }

              void print_2(void)

              {

              printf("print_2n");

              }

              #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ǔ)言斷言?xún)?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è)意交流的話(huà)請(qǐng)留下你寶貴的意見(jiàn)。

            c語(yǔ)言相關(guān)文章:c語(yǔ)言教程




            關(guān)鍵詞: C語(yǔ)言 斷言

            評(píng)論


            相關(guān)推薦

            技術(shù)專(zhuān)區(qū)

            關(guān)閉