麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > C > 正文

探討C語言的那些小秘密

2020-02-24 14:26:40
字體:
供稿:網(wǎng)友

c語言是重要的知識點(diǎn),它可以改善編程環(huán)境,幫助編寫易于移植和調(diào)試的程序,下文是武林技術(shù)頻道小編為大家?guī)淼奶接?a target="_blank">C語言的那些小秘密,一起去聽聽武林技術(shù)頻道小編給出的解析吧。

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

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

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

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

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

下面來看看一段代碼:

?

#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++);語句的時(shí)候不會出現(xiàn)錯(cuò)誤,進(jìn)而執(zhí)行了i++,所以其后的打印語句輸出值為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),看來的確我們有必要熟練的在代碼中使用它,但是什么東西的使用都是有規(guī)則的,assert的使用也不例外。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

?

#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é)果為:

?

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

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

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

?

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


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

?

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

?

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

}


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

?

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

?

#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é)果:

?

?

?

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

print_2
Press any key to continue

看了上面運(yùn)行結(jié)果可能有的讀者會很疑惑為什么會出現(xiàn)以上的錯(cuò)誤呢?!if語句的條件不滿足,那么print_value()函數(shù)應(yīng)該不會被調(diào)用啊,怎么會打印呢。如果我們把上面的printf_value()替換為 print_1();? print_2();,就會很清楚的發(fā)現(xiàn)if語句在此的作用僅僅是不調(diào)用print_1();,而print_2();在控制之外,所以出現(xiàn)了上面的結(jié)果,有的讀者可能會馬上想到我們加上一個(gè){}不就好了嗎,在這里的確是加一個(gè){}就可以了,因?yàn)檫@里是一個(gè)特殊情況,沒有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;
}


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

?

error C2181: illegal else without matching if

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

上面是武林技術(shù)頻道小編為大家?guī)淼奶接慍語言的那些小秘密,我們自己實(shí)現(xiàn)的斷言可以看作是一種比較經(jīng)典的斷言設(shè)計(jì)方法。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 久草视频在线资源 | 91久久国产露脸精品国产护士 | 久久老司机 | 久久国产一二区 | 国产精品av久久久久久网址 | 久久精品无码一区二区三区 | 成品片a免人视频 | 欧美一级毛片免费观看 | 91 久久| 欧美3p激情一区二区三区猛视频 | 国产精品入口夜色视频大尺度 | 国产在线观看91精品 | 色网站综合 | 久久久久久久一区 | 欧产日产国产精品v | 欧美色大成网站www永久男同 | 亚洲欧美国产高清 | 日本中文高清 | 国产69精品久久久久久 | 91九色视频| 国产精品自拍啪啪 | 国产精品成人久久久久a级 av电影在线免费 | 久草在线高清 | 青青国产在线视频 | 成人wxx视频免费 | 中文日韩在线 | 91视频久久| 日韩欧美色综合 | a视频网站 | 久草在线精品观看 | 国产免费观看一区二区三区 | 免费在线观看国产 | 蜜桃传媒视频麻豆第一区免费观看 | 国产精品久久久久久久久久久天堂 | 国产午夜电影在线观看 | 羞羞视频免费网站男男 | 91在线视频在线观看 | 在线视频观看一区二区 | 亚洲欧美国产精品va在线观看 | 91精品国产777在线观看 | 国产精品久久久久久久不卡 |