程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 商量C說話的那些小機密之斷言

商量C說話的那些小機密之斷言

編輯:關於C++

商量C說話的那些小機密之斷言。本站提示廣大學習愛好者:(商量C說話的那些小機密之斷言)文章只能為提供參考,不一定能成為您想要的結果。以下是商量C說話的那些小機密之斷言正文


每次寫摘要我都認為是一件很頭疼的事兒,由於我曉得摘要真的很主要,它簡直直接就決議了讀者的數目。能夠花了九六二虎之力寫出來的器械,由於摘要的掉敗而前功盡棄,由於絕年夜多半的讀者看文章之前都邑閱讀下摘要,假如他們發明摘要“纰謬口”,沒有甚麼特點和吸惹人的處所,那末輕則采取目下十行的辦法看完整文,重則對文章判“逝世刑”,一篇文章的利害固然不克不及用摘要來權衡,然則它卻經常被讀者用來權衡一篇文章的利害,從而成了文章讀者數目若干的一個症結身分。上面言歸正傳來講說斷言,假如出於普通性的進修C說話,敷衍測驗的話,我想很少有人會在代碼中應用斷言,能夠有的人在此之前歷來沒有應用過斷言。那末斷言的應用究竟能給我們的代碼帶來甚麼呢?我盡量的把我所懂得的斷言的應用講授清晰,願望我在此所講的斷言可以或許對你有所贊助,讓你今後可以或許在代碼中靈巧應用斷言。

在講授之前,我們先來對斷言做一個根本的引見,讓年夜家對斷言有一個年夜致的懂得。在應用C說話編寫工程代碼時,我們總會對某種假定前提停止檢討,斷言就是用於在代碼中捕獲這些假定,可以將斷言看做是異常處置的一種高等情勢。斷言表現為一些布爾表達式,法式員信任在法式中的某個特定點該表達式值為真。可以在任什麼時候候啟用和禁用斷言驗證,是以可以在測試時啟用斷言,而在安排時禁用斷言。異樣,法式投入運轉後,終究用戶在碰到成績時可以從新升引斷言。它可以疾速發明並定位軟件成績,同時對體系毛病停止主動報警。斷言可以對在體系中隱蔽很深,用其它手腕極難發明的成績可以用斷言來停止定位,從而延長軟件成績定位時光,進步體系的可測性。現實運用時,可依據詳細情形靈巧地設計斷言。

經由過程下面的講授我們關於斷言算是有了一個年夜概的懂得,那末接上去我們就來看看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說話代碼的進程中參考下。因為自己程度無限,文章中的不當或毛病的地方在所不免,殷切願望讀者批駁斧正。同時也迎接讀者配合商量相干的內容,假如願意交換的話請留下你名貴的看法。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved