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

首頁 > 編程 > C > 正文

探討C語言的那些小秘密

2020-02-24 14:26:40
字體:
來源:轉載
供稿:網友

c語言是重要的知識點,它可以改善編程環境,幫助編寫易于移植和調試的程序,下文是武林技術頻道小編為大家帶來的探討C語言的那些小秘密,一起去聽聽武林技術頻道小編給出的解析吧。

每次寫摘要我都覺得是一件很頭疼的事兒,因為我知道摘要真的很重要,它幾乎直接就決定了讀者的數量??赡芑司帕⒅懗鰜淼臇|西,因為摘要的失敗而前功盡棄,因為絕大多數的讀者看文章之前都會瀏覽下摘要,如果他們發現摘要“不對口”,沒有什么特色和吸引人的地方,那么輕則采用一目十行的方法看完全文,重則對文章判“死刑”,一篇文章的好壞雖然不能用摘要來衡量,但是它卻常常被讀者用來衡量一篇文章的好壞,從而成為了文章讀者數量多少的一個關鍵因素。下面言歸正傳來說說斷言,如果出于一般性的學習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
此時就不會在執行接下來的打印語句了??纯次覀冏约旱膶崿F方式就知道,我們自己編寫的斷言可以比直接調用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語言的那些小秘密,我們自己實現的斷言可以看作是一種比較經典的斷言設計方法。

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

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
视频在线一区二区| 日韩性生活视频| 国产精品视频大全| 最新日韩中文字幕| 国产999精品久久久| 欧美有码在线观看视频| 国产亚洲欧美一区| 国产一区二区久久精品| 成人深夜直播免费观看| 欧美国产精品va在线观看| 亚洲国产一区二区三区在线观看| 97av在线视频免费播放| 欧美乱人伦中文字幕在线| 91成人国产在线观看| 精品国产乱码久久久久久婷婷| 九九热精品视频国产| 91九色国产视频| 国产精品电影观看| 日韩理论片久久| 国产婷婷成人久久av免费高清| 日韩精品久久久久久福利| 伊人伊成久久人综合网站| 91免费国产视频| 俺去啦;欧美日韩| 77777少妇光屁股久久一区| 在线播放日韩欧美| 精品久久久一区二区| 亚州国产精品久久久| 国产精品美乳一区二区免费| 国产欧美婷婷中文| 精品亚洲va在线va天堂资源站| 日韩精品久久久久久久玫瑰园| 欧美大尺度在线观看| 538国产精品一区二区免费视频| 国产91成人在在线播放| 在线精品高清中文字幕| 国自产精品手机在线观看视频| 国产亚洲精品久久久久久777| 91热福利电影| 国产精品入口福利| 欧美精品久久久久久久免费观看| 欧美午夜丰满在线18影院| 中文字幕亚洲综合久久| 亚洲精品一区二三区不卡| 亚洲精品视频播放| 亚洲性猛交xxxxwww| 国产中文日韩欧美| 欧美激情视频在线| 日韩综合视频在线观看| 国产精品视频xxx| 欧美一级bbbbb性bbbb喷潮片| 亚洲aa在线观看| 一本色道久久综合狠狠躁篇的优点| 成人黄色av网站| 欧美精品videos性欧美| 欧美精品在线网站| 久久精品免费播放| 91九色蝌蚪国产| 国产日韩视频在线观看| 欧美激情一区二区三级高清视频| 亚洲国产成人一区| 亚洲摸下面视频| 97精品一区二区视频在线观看| 精品日韩美女的视频高清| 懂色av中文一区二区三区天美| 亚洲成人黄色网| 国产精品视频免费观看www| 日本三级韩国三级久久| 国产精品欧美日韩一区二区| 亚洲伊人久久综合| 欧美成人精品一区| 福利视频第一区| 美女国内精品自产拍在线播放| 亚洲一级黄色av| 日韩欧美一区二区三区| 亚洲国产成人一区| 欧美一级片在线播放| 中文字幕在线国产精品| 亚洲人成欧美中文字幕| 国产一区私人高清影院| 久久久噜噜噜久久久| 国产精品第二页| 欧美日韩一区二区三区在线免费观看| 亚洲精品电影网| 日韩av在线免播放器| 韩国福利视频一区| 亚洲精品短视频| 国产伦精品一区二区三区精品视频| 97香蕉超级碰碰久久免费的优势| 日韩美女主播视频| 国产精品色午夜在线观看| 日韩一中文字幕| 国产精品成人av性教育| 亚洲精品久久久久中文字幕二区| 亚洲欧美日韩中文在线| 91成人在线播放| 最新国产精品拍自在线播放| 夜夜嗨av色一区二区不卡| 国产亚洲免费的视频看| 久久久av网站| 97超级碰在线看视频免费在线看| 日韩在线一区二区三区免费视频| 日本不卡视频在线播放| 久久99热精品| 欧美激情a∨在线视频播放| 国产精品电影观看| 91色琪琪电影亚洲精品久久| 91sao在线观看国产| 欧美日韩成人精品| 色老头一区二区三区在线观看| 91国产精品91| 一本大道香蕉久在线播放29| 伊人久久男人天堂| 亚洲最大成人在线| 91免费视频网站| 亚洲免费影视第一页| 26uuu另类亚洲欧美日本一| 久久久久久国产精品三级玉女聊斋| 国产美女精彩久久| 国产成人精品视频| 亚洲欧洲国产精品| 亚洲天堂久久av| 精品视频9999| 精品偷拍各种wc美女嘘嘘| 国产欧美亚洲视频| 亚洲精品720p| 国产美女主播一区| 91国内揄拍国内精品对白| 色噜噜久久综合伊人一本| 成人免费黄色网| 国产精品免费视频xxxx| 久久人人爽人人爽爽久久| 亚洲视频在线观看网站| 成人免费观看网址| 亚洲欧洲国产精品| 国产精品香蕉国产| 91久久久久久久久| 欧美激情第一页xxx| 高清欧美性猛交xxxx黑人猛交| 国产精品91在线观看| 日韩在线观看成人| 国产精品人成电影| 欧美大片免费观看在线观看网站推荐| 久久天天躁狠狠躁夜夜爽蜜月| 福利视频导航一区| 日韩暖暖在线视频| 国产成人一区二区| 亚洲专区中文字幕| 国产91露脸中文字幕在线| 精品视频在线导航| 国产精品丝袜视频| 欧美国产欧美亚洲国产日韩mv天天看完整| 日韩精品在线私人| 亚洲女人被黑人巨大进入al| 97国产在线视频| 国产成人精品最新| 国产亚洲欧洲高清一区| 国产亚洲精品一区二区| 国产婷婷97碰碰久久人人蜜臀| 欧美电影在线免费观看网站| 日韩精品免费在线视频| 欧美精品激情在线观看| 国产女同一区二区| 91精品国产91久久久久久吃药|