核心中的資料型別

2021-05-22 05:28:45 字數 4298 閱讀 4249

第 11 章 核心中的資料型別

除了資料型別, 當編寫乙個驅動時有幾個其他的軟體問題要記住, 如果你想在 linux 平台間可移植.

乙個通常的規則是懷疑顯式的常量值. 常常通過使用預處理巨集, **已被引數化. 這一節列出了最重要的可移植性問題. 無論何時你遇到已被引數化的值, 你可以在標頭檔案中以及在隨官方核心發布的裝置驅動中找到提示.

當涉及時間間隔, 不要假定每秒有 1000 個嘀噠. 儘管當前對 i386 體系是真實的, 不是每個 linux 平台都以這個速度執行. 對於 x86 如果你使用 hz 值(如同某些人做的那樣), 這個假設可能是錯的, 並且沒人知道將來核心會發生什麼. 無論何時你使用嘀噠來計算時間間隔, 使用 hz ( 每秒的定時器中斷數 ) 來標定你的時間. 例如, 檢查乙個半秒的超時, 用 hz/2 和逝去時間比較. 更普遍地, msec 毫秒對應地嘀噠數一直是 msec*hz/1000.

當使用記憶體時, 記住乙個記憶體頁是 page_size 位元組, 不是 4kb. 假定頁大小是 4kb 並且硬編碼這個值是乙個 pc 程式設計師常見的錯誤, 相反, 被支援的平台顯示頁大小從 4 kb 到 64 kb, 並且有時它們在相同平台上的不同的實現上不同. 相關的巨集定義是 page_size 和 page_****. 後者包含將乙個位址移位來獲得它的頁號的位數. 對於 4kb 或者更大的頁這個數當前是 12 或者更大. 巨集在 中定義; 使用者空間程式可以使用 getpagesize 庫函式, 如果它們需要這個資訊.

讓我們看一下非一般的情況. 如果乙個驅動需要 16 kb 來暫存資料, 它不應當指定乙個 2 的指數 給 get_free_pages. 你需要乙個可移植解決方法. 這樣的解決方法, 幸運的是, 已經由核心開發者寫好並且稱為 get_order:

#include int order = get_order(16*1024);

buf = get_free_pages(gfp_kernel, order);

記住, get_order 的引數必須是 2 的冪.

小心不要假設位元組序. pc 儲存多位元組值是低位元組為先(小端為先, 因此是小端), 一些高階的平台以另一種方式(大端)工作. 任何可能的時候, 你的**應當這樣來編寫, 它不在乎它操作的資料的位元組序. 但是, 有時候乙個驅動需要使用單個位元組建立乙個整型數或者相反, 或者它必須與乙個要求乙個特定順序的裝置通訊.

包含檔案 定義了或者 __big_endian 或者 __little_endian, 依賴處理器的位元組序. 當處理位元組序問題時, 你可能編碼一堆 #ifdef __litttle_endian 條件語句, 但是有乙個更好的方法. linux 核心定義了一套巨集定義來處理之間的轉換, 在處理器位元組序和你需要以特定位元組序儲存和載入的資料之間. 例如:

u32 cpu_to_le32 (u32);

u32 le32_to_cpu (u32);

這 2 個巨集定義轉換乙個值, 從無論 cpu 使用的什麼到乙個無符號的, 小端, 32 位數, 並且轉換回. 它們不管你的 cpu 是小端還是大端, 不管它是不是 32-位 處理器. 在沒有事情要做的情況下它們原樣返回它們的引數. 使用這些巨集定義易於編寫可移植的**, 而不必使用大量的條件編譯建造.

有很多類似的函式; 你可以在 和 中見到完整列表. 一會兒之後, 這個模式不難遵循. be64_to_cpu 轉換乙個無符號的, 大端, 64-位 值到乙個內部 cpu 表示. le16_to_cpus, 相反, 處理有符號的, 小端, 16 位數. 當處理指標時, 你也會使用如 cpu_to_le32p, 它使用指向乙個值的指標來轉換, 而不是這個值自身. 剩下的看包含檔案.

編寫可移植**而值得考慮的最後乙個問題是如何訪問不對齊的資料 -- 例如, 如何讀取乙個儲存於乙個不是 4 位元組倍數的位址的4位元組值. i386 使用者常常訪問不對齊資料項, 但是不是所有的體系允許這個. 很多現代的體系產生乙個異常, 每次程式試圖不對齊資料傳送時; 資料傳輸由異常處理來處理, 帶來很大的效能犧牲. 如果你需要訪問不對齊的資料, 你應當使用下列巨集:

#include get_unaligned(ptr);

put_unaligned(val, ptr);

這些巨集是無型別的, 並且用在每個資料項, 不管它是 1 個, 2 個, 4 個, 或者 8 個位元組長. 它們在任何核心版本中定義.

關於對齊的另乙個問題是跨平台的資料結構移植性. 同樣的資料結構( 在 c-語言 原始檔中定義 )可能在不同的平台上不同地編譯. 編譯器根據各個平台不同的慣例來安排結構成員對齊.

為了編寫可以跨體系移動的資料使用的資料結構, 你應當一直強制自然的資料項對齊, 加上對乙個特定對齊方式的標準化. 自然對齊意味著儲存資料項在是它的大小的整數倍的位址上(例如, 8-byte 項在 8 的整數倍的位址上). 為強制自然對齊在阻止編譯器以不希望的方式安排成員量的時候, 你應當使用填充者成員來避免在資料結構中留下空洞.

為展示編譯器如何強制對齊, dataalign 程式在原始碼的 misc-progs 目錄中發布, 並且乙個對等的 kdataalign 模組是 misc-modules 的一部分. 這是程式在幾個平台上的輸出以及模組在 sparc64 的輸出:

arch align: char short int long ptr long-long u8 u16 u32 u64

i386 1 2 4 4 4 4 1 2 4 4

i686 1 2 4 4 4 4 1 2 4 4

alpha 1 2 4 8 8 8 1 2 4 8

armv4l 1 2 4 4 4 4 1 2 4 4

ia64 1 2 4 8 8 8 1 2 4 8

mips 1 2 4 4 4 8 1 2 4 8

ppc 1 2 4 4 4 8 1 2 4 8

sparc 1 2 4 4 4 8 1 2 4 8

sparc64 1 2 4 4 4 8 1 2 4 8

x86_64 1 2 4 8 8 8 1 2 4 8

kernel: arch align: char short int long ptr long-long u8 u16 u32 u64

kernel: sparc64 1 2 4 8 8 8 1 2 4 8

有趣的是注意不是所有的平台對齊 64-位值在 64-位邊界上, 因此你需要填充者成員來強制對齊和保證可移植性.

最後, 要知道編譯器可能自己悄悄地插入填充到結構中來保證每個成員是對齊的, 為了目標處理器的良好效能. 如果你定義乙個結構打算來匹配乙個裝置期望的結構, 這個自動的填充可能妨礙你的企圖. 解決這個問題的方法是告訴編譯器這個結構必須是"緊湊的", 不能增加填充者. 例如, 核心標頭檔案 定義幾個與 x86 bios 介面的資料結構, 並且它包含下列的定義:

struct

__attribute__ ((packed)) scsi;

如果沒有 __attribute__ ((packed)), lun 成員可能被在前面新增 2 個填充者位元組或者 6 個, 如果我們在 64-位平台上編譯這個結構.

很多內部核心函式返回乙個指標值給呼叫者. 許多這些函式也可能失敗. 大部分情況, 失敗由返回乙個 null 指標值來指示. 這個技術是能用的, 但是它不能通知問題的確切特性. 一些介面確實需要返回乙個實際的錯誤碼以便於呼叫者能夠基於實際上什麼出錯來作出正確的判斷.

許多核心介面通過在指標值中對錯誤值編碼來返回這個資訊. 這樣的資訊必須小心使用, 因為它們的返回值不能簡單地與 null 比較. 為幫助建立和使用這類介面, 一小部分函式已可用( 在 ).

乙個返回指標型別的函式可以返回乙個錯誤值, 使用:

void *err_ptr(long error);
這裡, error 是常見的負值錯誤碼. 呼叫者可用使用 is_err 來測試是否乙個返回的指標是不是乙個錯誤碼:

long is_err(const void *ptr);
如果你需要實際的錯誤碼, 它可能被抽取到, 使用:

long ptr_err(const void *ptr);
你應當只對 is_err 返回乙個真值的值使用 ptr_err; 任何其他的值是乙個有效的指標.

php核心 資料型別

結構體內每乙個變數都獨佔一塊記憶體,並保持記憶體對齊 聯合體內所有變數公用同一塊記憶體,占用記憶體大小為聯合體中占用記憶體最大的變數的記憶體大小 每個變數的結構定義 struct zval struct u v uint32 t type info u1 union u2 zend value表示變...

python核心資料型別

序列運算子 本文採用版本pyton3.5 數字 int,long,float,complex,bool 字元 str,unicode 列表 list 字典 dict 元組 tuple 檔案 file 其他型別 集合 set frozenset,類型別,none str repr 或format 將非...

js核心,命名, 基本資料型別,資料型別檢測

瀏覽器核心 ie trident 俗稱ie核心 chrome webkit blink 2013年 firefox gecko 俗稱firefox核心 opera blink presto safari webkit 命名規則 必須遵守,不遵守程式就會報錯 1.變數名使用 或者字母開頭,變數裡面可以...