Linux核心程式設計 實現斷言

2021-09-11 20:29:57 字數 2994 閱讀 9734

斷言是非常常見的,其語義就是判斷某個條件,如果不為真,就執行一段非常規的動作,一般為程式立馬結束執行。

斷言分為動態和靜態的。動態斷言也叫執行時斷言,即在程式執行的使用,由比較指令來判斷條件;而靜態斷言是在**的編譯過程中,通過編譯器對常量表示式的計算來判斷條件成立與否的,即一般不會生成額外的**。

一般我們在沒有編譯器特性支撐的情況下,可以使用c語言的語法語義的正確性來實現,最常規的是根據常量表示式的真假來定義乙個負數大小的陣列。比如:

#define static_assert(cond) \

do while(0)

cond必須要為常量表示式,即非執行時就可以確定結果的表示式。

當斷言失敗時將出現下面的資訊:

../../include/utils/compiler.h:247:20: error: size of unnamed array is negative
在有編譯器特性支援的的情況下,使用__attribuite__((error(message)))來描述乙個不存在的函式,當編譯時發現呼叫了此函式就列印message並終止編譯,一般來說,函式的存在與否必須要等到鏈結時才可知的,但gnu的編譯器支援這個特性。比如:

#define static_assert(cond) \

do } while(0)

同樣cond必須要為常量表示式,即非執行時就可以確定結果的表示式。

當斷言失敗時將出現下面的資訊:

../../include/utils/compiler.h:247:20: error: call to 『__static_assert_func』 declared with attribute error: static assert failed
核心使用build_bug_on_***()來作為字首定義一系列的靜態斷言,比如在定義乙個可以配置的雜湊表時,為了加快雜湊桶的定位,一般都是用2^n大小的桶,並用雜湊值與其掩碼來計算桶下標,即:hash_value & (bucket_size -1)。為了防止非2^n大小的雜湊表出現,定義build_bug_on_not_power_of_2()來快速判斷大小。

這些巨集都最終都是由下列巨集實現 :

#define gcc_version (__gnuc__ * 10000		\

+ __gnuc_minor__ * 100 \

+ __gnuc_patchlevel__)

#if gcc_version >= 40800

# define __compiletime_error(message) __attribute__((error(message)))

#endif

#ifndef __compiletime_error

# define __compiletime_error(message)

#endif

# define __compiletime_error_fallback(condition) \

do while (0)

#if defined(__optimize__)

# define __compiletime_assert(condition, msg, prefix, suffix) \

do while (0)

#else

# define __compiletime_assert(condition, msg, prefix, suffix) \

__compiletime_error_fallback(!(condition))

#endif

#define _compiletime_assert(condition, msg, prefix, suffix) \

__compiletime_assert(condition, msg, prefix, suffix)

#define compiletime_assert(condition, msg) \

_compiletime_assert(condition, msg, __compiletime_assert_, __line__)

#define build_bug_on(condition) \

build_bug_on_msg(condition, "build_bug_on failed: " #condition)

#define build_bug_on_not_power_of_2(n) \

build_bug_on((n) == 0 || (((n) & ((n) - 1)) != 0))

上面的定義做了一些改動,你可以直接用於自己的應用層程式。__optimize__表示在使用-o並且n大於0時,編譯器會定義此巨集,並且要gcc編譯器特性來斷言時,必須要使用較新的版本,我在macos上測試時,gcc就不支援__attribuite__((error(message)))這個擴充套件。

剛才我們提示過,動態的斷言將使用指令,完成斷言,那麼聰明的核心在條件不成立時執行乙個cpu不認識的指令來觸發乙個指令異常,並被異常子系統捕獲,最終會執行宕機處理。

#define bug() __asm__ __volatile__("ud2\n")
我們在應用層程式設計時,直接使用assert.h標頭檔案中的assert(cond)就可以了。

核心的斷言有許多的**技巧,你在掌握了基本原理後,可以在所有的bug.h中學習動態斷言,以及在compiler.hbuild_bug.h中學習靜態斷言。

《Windows核心程式設計》 防禦性程式設計 斷言

防禦性程式設計是提高軟體質量技術的有益輔助手段,它的主要思想是 子程式應該不因傳入錯誤資料而被破壞,哪怕是由其他子程式產生的錯誤資料。防禦性程式設計關鍵在於嚴格的輸入檢查 預期的錯誤處理方法。下面介紹使用斷言來進行防禦性程式設計。斷言通常是乙個例程 routine 或乙個巨集 macros 斷言通常...

《Windows核心程式設計》 防禦性程式設計 斷言

防禦性程式設計是提高軟體質量技術的有益輔助手段,它的主要思想是 子程式應該不因傳入錯誤資料而被破壞,哪怕是由其他子程式產生的錯誤資料。防禦性程式設計關鍵在於嚴格的輸入檢查 預期的錯誤處理方法。下面介紹使用斷言來進行防禦性程式設計。斷言通常是乙個例程 routine 或乙個巨集 macros 斷言通常...

Linux 核心程式設計總結

linux 核心程式設計總結 從事了幾年的核心程式設計,對核心程式設計有一定的經驗,現總結 吐槽下,作為標記。任何程序都有有程序的入口點,使用者態的程序,其入口點是,main函式。那麼核心的入口點是什麼?個人理解整個os,執行起來就是乙個程序,核心的入口點是init程序,在這個程序中負責 1 子程序...