【C語言學習趣事】_GCC原始碼分析_2_assert.h

來源:互聯網
上載者:User

  我記得在以前的一篇隨筆中,我堆windows下的<assert.h>進行了分析,今天我們來看看gcc中這個檔案的定義是怎樣的。

【1】assert宏的作用

  assert宏實現斷言的作用,一般在源檔案中引用格式如下:

#include <assert.h>#undef NDEBUGassert(expression)

關於assert宏:

  1、當 expression的值為0時進行斷言,如果運算式expression的值非零,則不進行斷言。

  2、assert宏進行斷言的時候,在標準錯誤輸出中輸出斷言發生的源檔案名稱:__FILE__ 和斷言發生時語句所在的行: __LINE__

  3、可在程式的調試過程中,利用assert宏進行關鍵點程式進行測試,以輸出一些有用的資訊,當不需要調試的時候,可以通過定義NDEBUG宏來取消

宏assert的作用。

【2】assert.h

/* Allow this file to be included multiple times   with different settings of NDEBUG.  *///assert 為C庫提供的一種斷言機制//斷言用來在標準錯誤輸出資料流輸出資訊,並且使程式異常終止/*    斷言的機制:*///首先取消 assert 宏的定義,//這樣做的目的是為了防止宏重複被定義#undef assert#undef __assert//通過判斷是否定義宏 NDEBUG 來判斷在原始碼中是否需要宏assert/*    如果定義了 NDEBUG 宏,就表示不需要在程式中引用 assert 宏    NDEBUG: do not debug    否則就在程式中,assert 宏將被執行    可以發現assert宏在定義 NDEBUG時,定義很特別,宏參數並沒有引用*/#ifdef NDEBUG    //定義了NDEBUG宏,assert 宏定義為不做任何提示輸出     #define assert(ignore)  ((void)0)#else    void __eprintf ();        /* Defined in gnulib */    #ifdef __STDC__    //定義了__STDC__宏        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__)))        #define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  expression, lineno, file), 0)    #else /* no __STDC__; i.e. -traditional.  */        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__)))        #define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  "expression", lineno, file), 0)    #endif /* no __STDC__; i.e. -traditional.  */#endif

View Code

【3】第一段預先處理

//首先取消 assert 宏的定義,//這樣做的目的是為了防止重複定義宏的影響#undef assert#undef __assert

  這樣做的目的是為了防止 assert 重定義,引起混亂;這樣在引用的位置處,就可以取消前面的定義。

【4】標準assert宏定義結構

  通常assert宏定義具有下面的結構

      

  這樣結構的目的是為了對使用者的 NDEBUG 宏做出正確的響應。

【5】宏代碼

//通過判斷是否定義宏 NDEBUG 來判斷在原始碼中是否需要宏assert/*    如果定義了 NDEBUG 宏,就表示不需要在程式中引用 assert 宏    NDEBUG: do not debug    否則就在程式中,assert 宏將被執行    可以發現assert宏在定義 NDEBUG時,定義很特別,宏參數並沒有引用*/#ifdef NDEBUG    //定義了NDEBUG宏,assert 宏定義為不做任何提示輸出     #define assert(ignore)  ((void)0)#else    void __eprintf ();        /* Defined in gnulib */    #ifdef __STDC__    //定義了__STDC__宏        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__)))        #define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  expression, lineno, file), 0)    #else /* no __STDC__; i.e. -traditional.  */        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__)))        #define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  "expression", lineno, file), 0)    #endif /* no __STDC__; i.e. -traditional.  */#endif

  這裡我們可以看到,這個宏,其實是定義了兩個紅: assert 和 __assert

1、assert

  分兩種情況: 

定義了 __STDC__ 宏時:

#define assert(expression)  \              ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__)))

未定義了 __STDC__ 宏時:

#define assert(expression)  \              ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__)))

  這兩者的區別,僅在於 “#” 串連符的作用,如果不用  #expression 這種形式,則宏參數不能使 帶引號的字串, 而用了

#expression 這種形式,assert宏的實際參數既可以是帶引號的字串。

兩個預定義宏:

  __FILE__: 返回C成員源檔案名稱

  __LINE__ :傳回碼行在C檔案中的行數

2、__assert

  這個宏只有一種形式:

#define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  "expression", lineno, file), 0)

  這個宏,其實是引用了函數 __eprintf() 函數來實現輸出,這個函數不是標準的庫函數。如果要實現標準assert宏,則不能引用標準庫

函數實現,這是因為如果在程式中如果沒有包含這些庫函數,則會引起異常。

__eprintf() 函數: 

#ifdef L_eprintf#include <stdio.h>/* This is used by the `assert' macro.  */void__eprintf (string, expression, line, filename)     char *string;     char *expression;     int line;     char *filename;{  fprintf (stderr, string, expression, line, filename);  fflush (stderr);  abort ();}#endif

  就是說這個標頭檔還可以這樣:

#ifdef NDEBUG    //定義了NDEBUG宏,assert 宏定義為不做任何提示輸出     #define assert(ignore)  ((void)0)#else    void __eprintf ();  /* Defined in gnulib */    #define __assert(expression, file, lineno)  \              (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n",    \                  expression, lineno, file), 0)        #ifdef __STDC__    //定義了__STDC__宏        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__)))        #else /* no __STDC__; i.e. -traditional.  */        #define assert(expression)  \              ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__)))    #endif /* no __STDC__; i.e. -traditional.  */#endif

【6】微軟VS 2008 代碼比較

/****assert.h - define the assert macro**       Copyright (c) Microsoft Corporation. All rights reserved.**Purpose:*       Defines the assert(exp) macro.*       [ANSI/System V]**       [Public]*****/#include <crtdefs.h>#undef  assert#ifdef  NDEBUG#define assert(_Expression)     ((void)0)#else#ifdef  __cplusplusextern "C" {#endif_CRTIMP void __cdecl _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);#ifdef  __cplusplus}#endif#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )#endif  /* NDEBUG */

 

  不知道,有沒有專門介紹gcc編譯器原始碼的書籍,我知道有一本書gcc internal, 是英語版的,看起來很廢力,有沒有人知道中文的這樣的書籍;

那位大俠不吝賜教,告訴我一本這樣的書,或者這樣的論壇,我找了好久也沒有發現一個合意的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.