[Linux]學習筆記系列 --GCC

文章目錄

  • 屬性
    • __cleanup
    • `__attribute_malloc__ 用于標記函數返回一個新分配的內存塊`
    • `__attribute_alloc_size__` 用于指定分配的內存大小
    • __attribute__((const)) 標記為純函數(pure function)
    • __attribute__((__externally_visible__)) 使其在編譯器優化過程中保持對外部模塊的可見性
    • __attribute__((__fallthrough__)) 帶有空語句的 fallthrough 屬性用作穿透語句
    • __must_check __warn_unused_result__
    • noinline 禁止內聯函數
    • __attribute__((__noreturn__)) 標記函數不會返回到調用者
    • __attribute__((__no_sanitize_address__)) 不需要執行內存錯誤檢測
      • 總結
    • __attribute__((__no_stack_protector__))
    • __no_profile 編譯器不應使用與配置文件相關的工具對函數進行操作
    • notrace 禁止跟蹤函數調用
    • __attribute__((__pure__)) 標記為純函數
      • `__pure` 的定義
      • 什么是純函數?
      • `__pure` 的作用
      • 使用場景
      • 注意事項
      • 總結
    • __printf 像 `printf` 一樣檢查格式字符串
    • __cleanup 在變量的作用域結束時自動調用指定的清理函數
      • **工作原理**
  • 聲明
    • `__fortify_function` 用于啟用額外的安全檢查,以防止常見的編程錯誤,如緩沖區溢出
    • **`__LEAF`** 告訴編譯器,該函數是一個葉函數(leaf function),即它不會調用其他函數
    • `__error__` 屬性告訴編譯器,如果該函數被調用,則會觸發編譯錯誤,并輸出指定的錯誤消息 `msg`
    • __wur 表示函數的返回值不應被忽略
    • __THROW && __NTH 聲明函數不會拋出任何異常
    • __nonnull 用于指示函數的某些參數不能為空指針
    • __errordecl 用于聲明編譯時錯誤信息
    • __REDIRECT 將一個函數重定向到另一個函數
  • 關鍵字
    • __restrict 用于指示指針或引用所指向的內存區域在當前作用域內不會被其他指針或引用所別名
    • __auto_type 自動推導變量的類型
      • **工作原理**
      • **限制**
      • **使用場景**
      • **總結**
  • 全局變量
    • `stderr` 標準錯誤輸出流
  • 內置函數
    • __builtin_clz __builtin_clzll 計算一個無符號整數的前導零的數量
    • __builtin_constant_p 檢查一個表達式是否是編譯時常量
    • __builtin_expect 用于分支預測
    • __builtin_return_address 獲取當前函數的返回地址
    • __builtin_unreachable 標記不可達代碼
    • `__builtin_object_size` 用于在編譯時確定指針所指向對象的大小
    • __builtin_prefetch 用于在程序運行時向處理器發出預取指令
    • __va_arg_pack 用于處理可變參數函數
    • __va_arg_pack_len 用于獲取可變參數的數量
  • 函數
    • exit
    • `perror` 接受一個字符串參數,并將該字符串作為前綴輸出到標準錯誤流
    • `fprintf` 將格式化的輸出寫入指定的文件流
      • 函數原型
      • 返回值
      • 源碼
    • fstat 獲取文件描述符 `fd` 對應文件的狀態信息
    • isalnum 檢查字符是否為字母或數字
    • isatty 檢查文件描述符是否指向一個終端設備
      • 參數
      • 返回值
    • getopt_core.h
      • getopt_long 處理長選項(即以雙破折號 `--` 開頭的選項)和短選項(即以單破折號 `-` 開頭的選項)
    • getenv **獲取環境變量**
    • dummy 虛擬變量
    • `##__VA_ARGS__` 用于處理可變參數宏
    • _Static_assert 編譯時斷言
  • 語法
    • ...
    • _Generic 用于實現類型安全的多態函數
      • **`_Generic` 簡介**
      • **使用場景**
      • **工作原理**
      • **實現細節**
      • **優缺點**
        • **優點**:
        • **缺點**:
      • **總結**

在這里插入圖片描述

https://github.com/wdfk-prog/linux-study

屬性

__cleanup

__attribute_malloc__ 用于標記函數返回一個新分配的內存塊

  • 這有助于編譯器進行優化,例如避免不必要的內存檢查。

__attribute_alloc_size__ 用于指定分配的內存大小

  • attribute_alloc_size__ ((1)) 是另一個 GCC 特定的擴展,用于指定分配的內存大小。參數 (1) 表示第一個參數 __size 是分配的內存大小。這有助于編譯器進行優化和靜態分析

attribute((const)) 標記為純函數(pure function)

純函數具有以下特性:

  1. 無副作用:純函數不依賴于任何可變的全局狀態,也不會修改任何全局狀態。這意味著函數的輸出僅依賴于其輸入參數,不會對程序的其他部分產生影響。
  2. 可優化:由于純函數的輸出僅依賴于輸入參數,編譯器可以進行更激進的優化。例如,編譯器可以將純函數的多次調用合并為一次調用,或者在調用純函數時進行常量傳播和代碼移動等優化。

attribute((externally_visible)) 使其在編譯器優化過程中保持對外部模塊的可見性

  • 用于標記函數或變量,使其在編譯器優化過程中保持對外部模塊的可見性。通常情況下,編譯器可能會優化掉未被直接引用的符號(函數或變量),但使用這個屬性可以防止這種優化。
  • 作用: 它確保標記的符號在鏈接時不會被移除,即使編譯器認為它沒有被使用。這對于動態鏈接庫(shared libraries)或模塊化程序設計非常重要,因為其他模塊可能需要訪問這些符號。

attribute((fallthrough)) 帶有空語句的 fallthrough 屬性用作穿透語句

  • 帶有空語句的 fallthrough 屬性用作穿透語句。它向編譯器暗示,在 switch 語句中跳轉到另一個 case 標簽或用戶定義標簽的語句是故意的,因此不應觸發 -Wimplicit-fallthrough 警告。穿透屬性在每個屬性列表中最多只能出現一次,并且不能與其他屬性混合。它只能在 switch 語句中使用(否則編譯器將發出錯誤),在先前的語句之后和邏輯上后續的 case 標簽或用戶定義標簽之前。

__must_check warn_unused_result

  • warn_unused_result屬性如果使用該屬性的函數調用者不使用其返回值,則會發出警告。這對于不檢查結果要么是安全問題,要么總是錯誤的函數很有用,比如realloc。
#define __must_check                    __attribute__((__warn_unused_result__))

noinline 禁止內聯函數

  • noinline 是一個 GCC 特定的屬性,用于禁止編譯器將函數內聯。內聯函數是一種優化技術,編譯器會將函數的代碼直接插入到調用該函數的地方,以減少函數調用的開銷。然而,在某些情況下,開發人員可能希望禁止內聯,以確保函數的行為和性能符合預期。

attribute((noreturn)) 標記函數不會返回到調用者

  • 一些標準庫函數,例如 abort 和 exit ,無法返回。GCC 會自動知道這一點。一些程序定義了自己的函數,這些函數永遠不會返回。您可以聲明它們為 noreturn 來告訴編譯器這一事實
  • 關鍵字 noreturn 告訴編譯器假設 fatal 無法返回。然后它可以進行優化,無需考慮如果 fatal 何時返回會發生什么。這使得代碼略微更優。更重要的是,它有助于避免未初始化變量的虛假警告。
  • 關鍵字 noreturn 不會影響當適用時的異常路徑:一個標記為 noreturn 的函數仍然可以通過拋出異常或調用 longjmp 返回調用者
  • 一個 noreturn 函數的返回類型不應該是 void

attribute((no_sanitize_address)) 不需要執行內存錯誤檢測

__no_sanitize_address__ 是一個編譯器屬性,通常用于禁用地址消毒器(Address Sanitizer, ASan)對特定函數或代碼段的檢查。以下是對其作用和使用場景的詳細解釋:

  1. 地址消毒器(ASan)簡介:
    Address Sanitizer 是一種內存錯誤檢測工具,廣泛用于捕獲諸如緩沖區溢出、堆棧溢出、使用未初始化內存等問題。它通過在編譯時插入額外的檢查代碼來檢測這些錯誤。然而,這些檢查可能會增加運行時開銷,或者在某些低級代碼中導致誤報。

  2. __no_sanitize_address__ 的作用:
    當一個函數或代碼段被標記為 __no_sanitize_address__ 時,編譯器會跳過對該部分代碼的 ASan 檢查。這意味著:

    • 該代碼不會受到 ASan 的額外檢查。
    • 可以避免 ASan 在某些低級操作(如直接操作內存或硬件寄存器)中產生的誤報。
    • 減少運行時開銷,特別是在性能關鍵的代碼中。

總結

__no_sanitize_address__ 是一個有用的工具,用于在特定場景下禁用 ASan 檢查。它在需要直接操作內存、優化性能或避免誤報時非常有用。然而,使用時需要謹慎,因為禁用 ASan 檢查可能會掩蓋潛在的內存錯誤。

attribute((no_stack_protector))

  • __no_stack_protector__ 是一個 GCC 特定的屬性,用于禁用棧保護功能。棧保護是一種安全機制,用于防止棧溢出攻擊,例如緩沖區溢出。它通過在函數調用時插入額外的檢查代碼來檢測棧的完整性。
  • 當一個函數被標記為 __no_stack_protector__ 時,編譯器將不會為該函數插入棧保護代碼。這可能會導致安全風險,因為攻擊者可以利用棧溢出漏洞來執行惡意代碼。

__no_profile 編譯器不應使用與配置文件相關的工具對函數進行操作

  • 在函數聲明上使用 no_profile_instrument_function 屬性來表示編譯器不應使用與配置文件相關的工具對函數進行操作,例如通過 -fprofile-generate / -fprofile-instr-generate / -fcs-profile-generate / -fprofile-arcs 標志來實現。

notrace 禁止跟蹤函數調用

__attribute__((__no_instrument_function__))

attribute((pure)) 標記為純函數

這段代碼定義了一個名為 __pure 的宏,它使用了 GCC 提供的 __attribute__((__pure__)) 屬性,并附帶了一個鏈接,指向 GCC 官方文檔中關于純函數(pure function)的說明。以下是對其的詳細解釋:

__pure 的定義

__pure 是一個宏,用于簡化對 GCC 的 __attribute__((__pure__)) 屬性的使用。通過定義宏,開發者可以在代碼中更方便地標記函數為“純函數”,同時提高代碼的可讀性和可移植性。

什么是純函數?

純函數(pure function)是指滿足以下條件的函數:

  1. 無副作用:函數不會修改全局狀態或影響外部環境(如全局變量、文件、I/O 等)。
  2. 確定性:函數的返回值僅依賴于其輸入參數,對于相同的輸入參數,函數始終返回相同的結果。

純函數的這些特性使得它們在編譯時更容易被優化。

__pure 的作用

通過為函數添加 __pure 屬性,開發者可以顯式告訴編譯器該函數是一個純函數。編譯器會利用這一信息進行以下優化:

  1. 消除冗余調用
    • 如果函數在同一作用域內被多次調用且輸入參數相同,編譯器可以只調用一次并緩存結果。
  2. 重新排序指令
    • 由于純函數沒有副作用,編譯器可以安全地調整其調用順序,以優化性能。
  3. 內聯優化
    • 編譯器可能會更傾向于將純函數內聯,從而減少函數調用的開銷。

使用場景

  1. 數學計算

    • 例如,計算平方根、絕對值等函數,這些函數的返回值僅依賴于輸入參數。
    __pure int square(int x) {return x * x;
    }
    
  2. 數據轉換

    • 將輸入數據轉換為另一種形式,而不修改全局狀態。
    __pure int to_uppercase(char c) {return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c;
    }
    
  3. 查找操作

    • 在只讀數據結構中查找值的函數也可以標記為純函數。

注意事項

  1. __attribute__((const)) 的區別

    • __pure 函數可以讀取全局變量的值,但不能修改它們。
    • __attribute__((const)) 是更嚴格的屬性,要求函數既不能修改全局狀態,也不能讀取全局變量。
  2. 正確使用

    • 如果一個函數被錯誤地標記為 __pure,但實際上具有副作用(如修改全局變量或執行 I/O 操作),可能會導致未定義行為或錯誤的優化結果。
  3. 編譯器支持

    • __pure 是 GCC 和 Clang 支持的擴展屬性,因此在其他編譯器中可能不可用。

總結

__pure 是一個用于標記純函數的宏,通過顯式聲明函數的純屬性,幫助編譯器進行更高效的優化。它適用于無副作用且返回值僅依賴于輸入參數的函數。在使用時需要確保函數符合純函數的定義,否則可能導致錯誤的優化行為。附帶的鏈接提供了 GCC 官方文檔的參考,便于開發者了解更多細節。

__printf 像 printf 一樣檢查格式字符串

  • format 屬性用于告訴編譯器某個函數的參數應該像 printf 函數那樣進行格式化檢查。
#define __printf(a, b)                  __attribute__((__format__(printf, a, b)))
__printf(4, 0)
  • 4 表示格式字符串是函數的第 4 個參數(從 1 開始計數,包括 this 指針或隱式參數)。
  • 0 表示該函數沒有可變參數列表(即沒有類似 … 的參數)。如果存在可變參數列表,則需要指定其起始位置

__cleanup 在變量的作用域結束時自動調用指定的清理函數

__cleanup 是一個 GCC 提供的屬性(attribute),用于在變量的作用域結束時自動調用指定的清理函數。它是一種基于作用域的資源管理機制,能夠有效減少手動管理資源釋放的復雜性,避免資源泄漏。


工作原理

  1. 定義清理函數:

    • 清理函數是一個普通的 C 函數,用于釋放資源或執行其他清理操作。
    • 該函數的參數通常是一個指向需要清理的變量的指針。
  2. 聲明變量時使用 __cleanup:

    • 在聲明變量時,通過 __cleanup 屬性指定清理函數。
    • 當變量超出其作用域時,編譯器會自動調用指定的清理函數。
  3. 作用域結束時自動調用:

    • 當變量的作用域結束(如函數返回或代碼塊結束)時,清理函數會被自動調用,無需顯式調用。

聲明

__fortify_function 用于啟用額外的安全檢查,以防止常見的編程錯誤,如緩沖區溢出

__LEAF 告訴編譯器,該函數是一個葉函數(leaf function),即它不會調用其他函數

  • 葉函數的屬性允許編譯器進行進一步的優化,例如減少函數調用的開銷和棧空間的使用。

__error__ 屬性告訴編譯器,如果該函數被調用,則會觸發編譯錯誤,并輸出指定的錯誤消息 msg

# define __errordecl(name, msg) \extern void name (void) __attribute__((__error__ (msg)))

__wur 表示函數的返回值不應被忽略

  • __wur__attribute__ ((__warn_unused_result__)) 的縮寫,表示函數的返回值不應被忽略。這有助于防止內存泄漏,因為調用者必須處理返回的指針

__THROW && __NTH 聲明函數不會拋出任何異常

__nonnull 用于指示函數的某些參數不能為空指針

  • 這有助于編譯器進行靜態分析,檢測潛在的錯誤,并在編譯時發出警告或錯誤信息,從而提高代碼的安全性和可靠性。
  • 語法為 __attribute__((nonnull (arg_index1, arg_index2, ...))),其中 arg_index 是參數的索引,從 1 開始。
extern int __lxstat (int __ver, const char *__filename,struct stat *__stat_buf) __THROW __nonnull ((2, 3));
  • __nonnull ((3)) :這表示 __fxstat 函數的第2和3個參數(即 __stat_buf)不能為空指針。如果在調用 __fxstat 函數時傳遞了空指針作為第三個參數,編譯器會在編譯時發出警告或錯誤信息。

__errordecl 用于聲明編譯時錯誤信息

# define __errordecl(name, msg) \extern void name (void) __attribute__((__error__ (msg)))

__REDIRECT 將一個函數重定向到另一個函數

  • 將openalias重定向到open函數
extern int __REDIRECT (__open_alias, (const char *__path, int __oflag, ...),open) __nonnull ((1));

關鍵字

__restrict 用于指示指針或引用所指向的內存區域在當前作用域內不會被其他指針或引用所別名

  • 在 C99 標準中,restrict 是標準關鍵字。在某些編譯器實現中,可能使用 __restrict 作為擴展。
  • 通過使用 __restrict,開發人員可以告訴編譯器,在當前作用域內,通過該指針訪問的內存區域不會與其他指針訪問的內存區域重疊。這使得編譯器可以進行更激進的優化,例如更好地利用寄存器和減少內存訪問,從而提高程序的性能。

__auto_type 自動推導變量的類型

__auto_type 是 GCC(GNU Compiler Collection)編譯器提供的一個擴展關鍵字,用于自動推導變量的類型。它類似于 C++ 中的 auto 關鍵字,但專門用于 C 語言中。__auto_type 的主要作用是讓編譯器根據初始化表達式的類型自動推導變量的類型,從而簡化代碼書寫并提高可讀性。


工作原理

  1. 類型推導:

    • 使用 __auto_type 聲明的變量,其類型由初始化表達式的類型決定。
    • 編譯器在編譯時會自動推導出變量的具體類型。
  2. 作用范圍:

    • __auto_type 只能用于局部變量的聲明,不能用于全局變量或函數參數。
  3. 編譯器支持:

    • __auto_type 是 GCC 的擴展功能,可能不被其他編譯器(如 MSVC)支持。

  1. 簡化代碼:

    • 減少了顯式類型聲明的冗余,尤其是在類型復雜的情況下。
  2. 增強可讀性:

    • 代碼更簡潔,開發者可以專注于邏輯而非類型聲明。
  3. 類型安全:

    • 在宏中使用時,__auto_type 可以確保變量的類型與初始化表達式一致,避免類型錯誤。
  4. 靈活性:

    • 適用于各種類型,包括基本類型、指針、結構體等。

限制

  1. 編譯器依賴:

    • __auto_type 是 GCC 的擴展功能,可能不被其他編譯器支持。
  2. 作用范圍有限:

    • 只能用于局部變量,不能用于全局變量或函數參數。
  3. 可讀性問題:

    • 對于不熟悉 __auto_type 的開發者,可能會增加理解代碼的難度。

使用場景

  1. 簡化類型聲明:

    • 在類型復雜或不易確定的情況下,使用 __auto_type 可以減少顯式類型聲明的負擔。
  2. 宏定義:

    • 在宏中使用 __auto_type 可以增強類型安全性,避免類型錯誤。
  3. 泛型操作:

    • 通過 __auto_type 實現類似泛型的功能,例如交換變量、比較大小等。

總結

__auto_type 是 GCC 提供的一個強大工具,用于在 C 語言中實現類型推導。它可以顯著簡化代碼書寫,提高代碼的可讀性和類型安全性,特別適合在宏定義和泛型操作中使用。然而,由于其是編譯器擴展功能,在使用時需要注意兼容性問題。

全局變量

stderr 標準錯誤輸出流

  • stderr 是標準錯誤輸出流,通常用于輸出錯誤和警告信息。在大多數操作系統中,stderr 是一個全局的文件流,默認情況下輸出到控制臺或終端。stderr 流的處理由操作系統和 C 標準庫管理。通常,stderr 流是無緩沖的,這意味著每次寫入操作都會立即輸出到終端或控制臺
  • 多線程環境中的 stderr 處理在多線程環境中,如果多個線程同時向 stderr 流寫入數據,可能會導致輸出混亂。

內置函數

__builtin_clz __builtin_clzll 計算一個無符號整數的前導零的數量

  • __builtin_clz 用于計算一個無符號整數(unsigned int)的前導零的數量。前導零是指從最高有效位(最左邊的位)開始,連續的零的數量

  • __builtin_clzll 用于計算一個無符號長長整數(unsigned long long)的前導零的數量。它的工作原理與 __builtin_clz 類似,只是它處理的是更大的數據類型。

__builtin_constant_p 檢查一個表達式是否是編譯時常量

  • GCC 編譯器提供的一個內建函數,用于檢查一個表達式是否是編譯時常量。它在編譯期間進行評估,并返回一個布爾值,指示給定的表達式是否為常量.這個函數通常用于條件編譯或優化代碼,以便在編譯時確定某些條件是否成立,從而避免在運行時進行不必要的計算。

  • 您可以使用內置函數 __builtin_constant_p 來判斷表達式 exp 在編譯時是否已知為常量,因此 GCC 可以對涉及該值的表達式執行常量折疊。該函數的參數是要測試的表達式。表達式不會被評估,副作用會被丟棄。如果參數是已知為編譯時常量的整數 1,如果不是已知為編譯時常量則返回 0。任何具有副作用的表達式都會使函數返回 0。返回 0 并不表示表達式不是常量,而只是表示 GCC 無法在活動優化選項集的約束內證明它是常量。

  • 通常您會在內存資源至關重要的嵌入式應用程序中使用此函數。如果您有一些復雜的計算,可能希望它在涉及常量時進行折疊,但不涉及常量時調用函數。

__builtin_expect 用于分支預測

  • GCC 編譯器提供的一個內建函數,用于分支預測。它允許開發人員向編譯器提供有關條件表達式的預期結果的信息,從而幫助編譯器進行更好的優化。__builtin_expect 函數通常用于性能敏感的代碼中,以提高分支預測的準確性,從而減少 CPU 的分支預測失敗率,提高程序的執行效率。
  • 這個函數的語法如下:
long __builtin_expect (long exp, long c);
  • exp 參數是要預測的表達式,c 參數是預期的結果。這個函數返回 exp 的值,但編譯器會根據 c 的值進行優化,以提高分支預測的準確性。
  • 這個函數通常用于性能敏感的代碼中,以提高分支預測的準確性,從而減少 CPU 的分支預測失敗率,提高程序的執行效率。它可以用于條件語句、循環和其他需要分支預測的地方。

__builtin_return_address 獲取當前函數的返回地址

  • GCC 編譯器提供的一個內建函數,用于獲取當前函數的返回地址。它通常用于調試和錯誤檢查,以便在運行時獲取函數調用的返回地址。這對于跟蹤函數調用棧和調試程序非常有用。
void * __builtin_return_address (unsigned int level);
  • level 參數指定要獲取的返回地址的級別。level 為 0 時,返回當前函數的返回地址;level 為 1 時,返回調用當前函數的函數的返回地址;以此類推。這個函數通常用于調試和錯誤檢查,以便在運行時獲取函數調用的返回地址。這對于跟蹤函數調用棧和調試程序非常有用。
  • 這個函數的返回值是一個指針,指向當前函數的返回地址。這個地址可以用于調試和錯誤檢查,以便在運行時獲取函數調用的返回地址。這對于跟蹤函數調用棧和調試程序非常有用。

__builtin_unreachable 標記不可達代碼

  • GCC 編譯器提供的一個內建函數,用于標記不可達代碼。它告訴編譯器在執行到該位置時,程序將不會繼續執行下去。這可以幫助編譯器進行更好的優化,因為它可以假設在這個位置之后的代碼永遠不會被執行。使用這個函數可以提高代碼的性能,并且在調試時可以幫助開發人員識別潛在的錯誤或不一致之處。
  • 這個函數通常用于在編譯器優化時提供提示,告訴編譯器某些代碼永遠不會被執行。這可以幫助編譯器進行更好的優化,并且在調試時可以幫助開發人員識別潛在的錯誤或不一致之處。

__builtin_object_size 用于在編譯時確定指針所指向對象的大小

  • __builtin_object_size 是 GCC 編譯器提供的一個內置函數,用于在編譯時確定指針所指向對象的大小。
  • 該函數接受兩個參數:
    • 第一個參數是指針 ptr
    • 第二個參數是一個常量整數,用于指定計算對象大小的方式。值 0 表示返回對象的最大已知大小

__builtin_prefetch 用于在程序運行時向處理器發出預取指令

  • __builtin_prefetch 是 GCC 編譯器提供的一個內置函數,用于在程序運行時向處理器發出預取指令。它允許開發人員在訪問數據之前,提前將數據加載到 CPU 的緩存中,從而提高程序的性能。
  • 這個函數通常用于性能敏感的代碼中,以提高數據訪問的速度。它可以用于循環、數組訪問和其他需要頻繁訪問數據的地方。使用 __builtin_prefetch 可以減少 CPU 的緩存未命中率,從而提高程序的性能。
  • 預取指令的目的是將指定的內存地址加載到緩存中,以減少后續訪問該地址時的延遲。這種優化對于性能關鍵的代碼非常有用,尤其是在處理大量數據或需要頻繁訪問內存的場景中
  • 需要注意的是,__builtin_prefetch 是一種低級優化工具,只有在性能瓶頸明確且經過分析驗證時才應使用。不當的預取可能會導致性能下降,例如浪費緩存空間或增加內存帶寬壓力。此外,預取的效果依賴于硬件架構和緩存行為,因此在不同平臺上的表現可能有所不同。

__builtin_prefetch 的基本語法如下:

__builtin_prefetch(const void *addr, int rw, int locality);
  • addr: 要預取的內存地址。通常是一個指針,指向即將被訪問的數據。
  • rw: 指定預取的類型。0 表示只讀預取,1 表示寫預取(即數據將被修改)。
  • locality: 指定數據的局部性,范圍為 0 到 3。值越高,表示數據在緩存中保留的時間越長:
    0: 數據很快會被訪問一次,不需要長時間保留。
    3: 數據會被頻繁訪問,需要盡可能長時間保留在緩存中。

__va_arg_pack 用于處理可變參數函數

__va_arg_pack_len 用于獲取可變參數的數量

函數

exit

  • 錯誤碼參考include/linux/errno.h

perror 接受一個字符串參數,并將該字符串作為前綴輸出到標準錯誤流

perror(filename);

perror 函數接受一個字符串參數,并將該字符串作為前綴輸出到標準錯誤流(stderr),后面跟隨一個冒號和一個空格,然后是與當前 errno 值對應的錯誤消息。

  • filename 是傳遞給 perror 的字符串參數,通常表示發生錯誤的文件的名稱。
  1. 錯誤信息輸出

    • 當文件操作失敗時,例如打開文件、讀取文件或寫入文件失敗,errno 會被設置為相應的錯誤代碼。
    • perror(filename) 會輸出類似于以下格式的錯誤信息:
      filename: No such file or directory
      
    • 其中,filename 是傳遞給 perror 的字符串,No such file or directory 是與 errno 值對應的錯誤消息。

fprintf 將格式化的輸出寫入指定的文件流

  • 它的功能類似于 printf,但 fprintf 允許你指定輸出的目標文件流,而不僅僅是標準輸出(stdout)。

函數原型

int fprintf(FILE *stream, const char *format, ...);
  • stream:目標文件流,指定輸出的目標。例如,stderr 表示標準錯誤輸出流。
  • format:格式字符串,指定輸出的格式。
  • ...:可變參數,根據格式字符串指定的格式,提供相應的值。

返回值

  • 成功時,返回寫入的字符數。
  • 失敗時,返回負值。

源碼

  • 定義了一個增強的 fprintf 函數版本,用于在編譯時進行額外的安全檢查。這段代碼利用了編譯器的特性來提高函數的安全性和可靠性。
# ifdef __va_arg_pack //__va_arg_pack 是一個編譯器特性,通常用于處理可變參數函數。
// __fortify_function 是一個編譯器特性,用于啟用額外的安全檢查,以防止常見的編程錯誤,如緩沖區溢出
__fortify_function int
fprintf (FILE *__restrict __stream, const char *__restrict __fmt, ...)
{return __fprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,__va_arg_pack ());
}
#endif

fstat 獲取文件描述符 fd 對應文件的狀態信息

  • fstat 函數返回 0 表示成功,返回 -1 表示失敗并設置 errno

isalnum 檢查字符是否為字母或數字

  1. 函數聲明

    int isalnum(int c);
    
    • isalnum 函數接受一個整數參數 c,表示要檢查的字符。
    • 返回值為非零值(通常為 1)表示字符是字母或數字,返回 0 表示字符不是字母或數字。
  2. 用途

    • isalnum 函數用于判斷字符是否屬于字母(包括大寫和小寫字母)或數字(0-9)。
    • 這是一個常用的字符分類函數,在處理字符串和字符數據時非常有用。

isatty 檢查文件描述符是否指向一個終端設備

參數

  • fd:一個整數,表示文件描述符。常見的文件描述符包括:
    • 0:標準輸入(stdin)
    • 1:標準輸出(stdout)
    • 2:標準錯誤輸出(stderr)

返回值

  • 如果文件描述符指向一個終端設備,isatty 返回非零值(通常為 1)。
  • 如果文件描述符不指向一個終端設備,isatty 返回 0。

getopt_core.h

  • optarg 是一個指向字符的指針,用于存儲當前選項的參數值
  • optind 是一個整數,表示下一個要掃描的 ARGV 元素的索引
  • opterr 是一個整數,用于控制 getopt 函數是否打印未識別選項的錯誤消息
  • optopt 是一個整數,用于存儲未識別的選項字符

getopt_long 處理長選項(即以雙破折號 -- 開頭的選項)和短選項(即以單破折號 - 開頭的選項)

  1. 函數聲明

    int getopt_long(int argc, char *const argv[], const char *optstring,const struct option *longopts, int *longindex);
    
    • getopt_long 函數接受五個參數:
      • argc:命令行參數的數量。
      • argv:命令行參數的數組。
      • optstring:一個字符串,包含短選項的字符。如果一個選項需要參數,其后應跟一個冒號 :
      • longopts:一個指向 struct option 數組的指針,定義了長選項。
      • longindex:一個指向整數的指針,用于存儲當前匹配的長選項在 longopts 數組中的索引。
  2. 返回值

  • getopt_long 無法匹配到命令行選項時,它會返回 ?
  • 如果遇到未知選項或選項缺少必需的參數,getopt_long 也會返回 ?
  1. struct option 結構體

    struct option {const char *name;int has_arg;int *flag;int val;
    };
    
    • struct option 結構體用于定義長選項:
      • name:長選項的名稱。
      • has_arg:指示選項是否需要參數。取值可以是 no_argumentrequired_argumentoptional_argument
      • flag:如果為 NULL,則返回 val 作為選項的值;否則,將 val 存儲在 flag 指向的變量中,并返回 0。
      • val:選項的值或標志。
  2. 使用示例

    int main(int argc, char *argv[]) {int opt;struct option longopts[] = {{"help", no_argument, NULL, 'h'},{"version", no_argument, NULL, 'v'},{"output", required_argument, NULL, 'o'},{0, 0, 0, 0}};while ((opt = getopt_long(argc, argv, "hvo:", longopts, NULL)) != -1) {switch (opt) {case 'h':printf("Usage: ...\n");break;case 'v':printf("Version: ...\n");break;case 'o':printf("Output: %s\n", optarg);break;default:fprintf(stderr, "Unknown option\n");exit(EXIT_FAILURE);}}return 0;
    }
    

getenv 獲取環境變量

  • getenv 是一個標準庫函數,用于獲取環境變量的值。
  • getenv 函數接受一個字符串參數,表示環境變量的名稱,并返回一個指向該環境變量值的指針。如果環境變量不存在,則返回 NULL
echo $KCONFIG_SEED # 顯示環境變量的值

dummy 虛擬變量

  • dummy 是一個虛擬參數,用于確保宏展開時參數列表的長度一致。在 __count_args 宏中,dummy 被用作第一個參數,以確保即使沒有傳遞任何參數,參數列表的長度也至少為 1。
/** 計算可變參數宏的參數數。目前只需要* 它用于 1、2 或 3 個參數。*/
#define __arg6(a1, a2, a3, a4, a5, a6, ...) a6
#define __count_args(...) __arg6(dummy, ##__VA_ARGS__, 4, 3, 2, 1, 0)

##__VA_ARGS__ 用于處理可變參數宏

  • ##__VA_ARGS__ 是一個預處理器技巧,用于處理可變參數宏。VA_ARGS 是一個特殊的宏參數,表示傳遞給宏的所有可變參數。## 是預處理器的連接運算符,用于將兩個標識符連接在一起。
/** 計算可變參數宏的參數數。目前只需要* 它用于 1、2 或 3 個參數。*/
#define __arg6(a1, a2, a3, a4, a5, a6, ...) a6
#define __count_args(...) __arg6(dummy, ##__VA_ARGS__, 4, 3, 2, 1, 0)

_Static_assert 編譯時斷言

_Static_assert(EVT_COUNT < 256, "Can only support 256 event types with 8 bits");

語法

  • ... 是一個特殊的語法,用于表示可變參數列表。它允許函數接受不定數量的參數,通常用于實現可變參數函數(variadic functions)。可變參數函數可以接受任意數量和類型的參數,這在處理不確定數量的輸入時非常有用。
  • gcc 擴展語法
u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
  1. [0 ... NR_CPUS-1] 是一個范圍表達式,表示從 0 到 NR_CPUS-1 的所有索引。
  2. … 表示范圍內的所有元素都將被初始化為 MPIDR_INVALID
Switch (i) {case 0 ... 10:printf("i is between 0 and 10\n");break;case 11 ... 20:printf("i is between 11 and 20\n");break;default:printf("i is greater than 20\n");break;
}

_Generic 用于實現類型安全的多態函數

_Generic 簡介

_Generic 是 C11 標準引入的一種關鍵字,用于實現類型泛型(type-generic programming)。它允許開發者根據表達式的類型選擇不同的代碼路徑,從而實現類似于函數重載的功能。_Generic 提供了一種在編譯時根據類型分發邏輯的機制,而無需運行時判斷。


使用場景

  1. 類型安全的多態函數

    • 在 C 中,函數重載并不被直接支持。通過 _Generic,可以根據參數的類型選擇不同的實現,從而實現類似于 C++ 中函數重載的功能。
    • 例如:為不同類型的輸入調用不同的處理函數。
  2. 簡化代碼邏輯

    • 在需要對不同類型執行不同操作的場景中,_Generic 可以避免冗長的 if-elseswitch 語句。
  3. 提高代碼可讀性和可維護性

    • 通過 _Generic,可以將類型分發邏輯集中到一個地方,減少重復代碼。
  4. 內核開發和底層優化

    • 在 Linux 內核或其他底層代碼中,_Generic 常用于為不同類型的同步原語(如自旋鎖、互斥鎖等)提供統一的接口。

工作原理

_Generic 的基本語法如下:

_Generic(expression, type1: result1, type2: result2, ..., default: default_result)
  • expression:需要判斷類型的表達式。
  • type1, type2, ...:列出可能的類型。
  • result1, result2, ...:對應類型的返回值或代碼路徑。
  • default(可選):當 expression 的類型不匹配任何列出的類型時,選擇的默認結果。

實現細節

  1. 編譯時類型檢查

    • _Generic 在編譯時解析表達式的類型,并選擇匹配的分支。這種機制避免了運行時的類型判斷,提高了性能。
  2. 類型匹配規則

    • _Generic 使用嚴格的類型匹配規則。例如,intunsigned int 是不同的類型,必須分別列出。
    • 如果沒有匹配的類型且未提供 default 分支,編譯器會報錯。
  3. 與宏結合

    • _Generic 通常與宏結合使用,以實現更靈活的接口。例如,可以為不同類型的輸入調用不同的函數。
  4. 嵌套使用

    • _Generic 可以嵌套使用,以處理更復雜的類型分發邏輯。

優缺點

優點
  1. 類型安全
    • _Generic 在編譯時進行類型檢查,避免了運行時錯誤。
  2. 性能高效
    • 類型分發邏輯在編譯時完成,不會增加運行時開銷。
  3. 代碼簡潔
    • 避免了冗長的 if-elseswitch 語句,提高了代碼的可讀性。
缺點
  1. 類型匹配限制
    • _Generic 需要顯式列出所有可能的類型,無法處理動態類型。
  2. 復雜性
    • 對于復雜的類型分發邏輯,代碼可能變得難以維護。
  3. 兼容性
    • _Generic 是 C11 標準的一部分,不支持 C11 的編譯器無法使用。

總結

_Generic 是 C11 提供的一種強大工具,用于實現類型安全的多態函數和類型分發邏輯。它在編譯時根據表達式的類型選擇代碼路徑,既提高了性能,又增強了代碼的可讀性和安全性。盡管存在一些限制,但在需要處理多種類型的場景中,_Generic 是一種非常實用的解決方案,尤其是在底層開發和性能優化中。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91407.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91407.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91407.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【龍澤科技】汽車維護與底盤拆裝檢修仿真教學軟件【風光580】

產品簡介汽車維護與底盤拆裝檢修仿真教學軟件是依托《全國職業院校技能大賽》“汽車維修”賽項中“汽車維護與底盤拆裝檢修模塊”競賽模塊&#xff0c;自主開發的一款仿真教學軟件。軟件采用仿真仿真技術模擬實際汽車維修工的崗位技能操作流程&#xff0c;操作內容主要包括&…

Spring之【循環引用】

目錄前置知識SingletonBeanRegistryDefaultSingletonBeanRegistrySpring中處理循環引用的流程分析定義兩個具有循環引用特點的Bean執行A的實例化執行A的屬性填充(執行過程中發現A依賴B&#xff0c;就去執行B的實例化邏輯)執行B的實例化執行B的屬性填充執行B的初始化執行A的屬性…

LRU緩存淘汰算法的詳細介紹與具體實現

LRU&#xff08;Least Recently Used&#xff0c;最近最少使用&#xff09;是一種基于時間局部性原理的緩存淘汰策略。其核心思想是&#xff1a;最近被訪問的數據在未來更可能被再次使用&#xff0c;而最久未被訪問的數據應優先被淘汰&#xff0c;從而在有限的緩存空間內保留高…

JS-第十九天-事件(一)

一、事件基礎概念1.1 事件三要素事件源&#xff1a;觸發事件的元素事件類型&#xff1a;事件的種類&#xff08;如click、mouseover等&#xff09;事件處理程序&#xff1a;響應事件的函數1.2 事件流機制事件傳播分為三個階段&#xff1a;捕獲階段&#xff1a;事件從頂層開始&a…

Matplotlib(三)- 圖表輔助元素

文章目錄一、圖表輔助元素簡介二、坐標軸的標簽、刻度范圍和刻度標簽1. 坐標軸標簽1.1 x軸標簽1.2 y軸標簽1.3 示例&#xff1a;繪制天氣氣溫折線圖2. 刻度范圍和刻度標簽2.1 刻度范圍2.1.1 x軸刻度范圍2.1.2 y軸刻度范圍2.2 刻度標簽2.2.1 x軸刻度標簽2.2.2 y軸刻度標簽2.3 示…

【Linux基礎知識系列】第七十八篇 - 初識Nmap:網絡掃描工具

在網絡管理和安全領域&#xff0c;網絡掃描是一個不可或缺的工具。它可以幫助網絡管理員了解網絡中的設備、服務以及潛在的安全漏洞。Nmap&#xff08;Network Mapper&#xff09;是一個功能強大的開源網絡掃描工具&#xff0c;它能夠快速發現網絡中的主機、端口和服務&#xf…

EasyGBS的兩種錄像回看

EasyGBS 支持兩種錄像回看&#xff0c;即“平臺端”的錄像回看和“設備端”的錄像回看。本期我們來介紹兩者的區別和使用方法。一、平臺端錄像1、什么是平臺端錄像平臺端錄像是指由 EasyGBS 平臺直接錄制并存儲。2、配置平臺端錄像進入平臺&#xff0c;依次點擊【錄像回放】→【…

大模型學習思路推薦!

為進一步貫徹落實中共中央印發《關于深化人才發展體制機制改革的意見》和國務院印發《關于“十四五”數字經濟發展規劃》等有關工作的部署要求&#xff0c;深入實施人才強國戰略和創新驅動發展戰略&#xff0c;加強全國數字化人才隊伍建設&#xff0c;持續推進人工智能從業人員…

數據庫連接池性能優化實戰

背景我們公司正在處于某個項目的維護階段&#xff0c;領導對資源告警比較重視&#xff0c;服務器資源告警的就不說了&#xff0c;運維同學每隔一小時都會檢測線上環境的應用服務信息&#xff0c;例如&#xff1a;網關日志響應時間告警/nginx日志接口響應時間告警/日志關鍵字異常…

Excel常用函數大全,非常實用

一、數學與統計函數1. SUM作用&#xff1a;求和SUM(number1, [number2], ...)SUM(A1:A10) ? 計算A1到A10單元格的總和注意&#xff1a;自動忽略文本和空單元格2. AVERAGE作用&#xff1a;計算平均值AVERAGE(number1, [number2], ...)AVERAGE(B2:B20) ? 計算B列20個數據的平均…

性能優化(一):時間分片(Time Slicing):讓你的應用在高負載下“永不卡頓”的秘密

性能優化(一)&#xff1a;時間分片&#xff08;Time Slicing&#xff09;&#xff1a;讓你的應用在高負載下“永不卡頓”的秘密 引子&#xff1a;那張讓你瀏覽器崩潰的“無限列表” 想象一個場景&#xff1a;你需要渲染一個包含一萬個項目的列表。在我們的“看不見”的應用中&a…

《C++》STL--list容器詳解

在 C 標準模板庫(STL)中&#xff0c;list 是一個非常重要的序列容器&#xff0c;它實現了雙向鏈表的數據結構。與 vector 和 deque 不同&#xff0c;list 提供了高效的插入和刪除操作&#xff0c;特別是在任意位置。本文將深入探討 list 容器的特性、使用方法以及常見操作。 文…

Day 28:類的定義和方法

DAY 28 類的定義和方法 知識點學習 1. 類的定義 在Python中&#xff0c;類是創建對象的模板。使用class關鍵字來定義一個類。類名通常采用首字母大寫的命名方式&#xff08;PascalCase&#xff09;。 # 最簡單的類定義 class MyClass:pass # 使用pass占位符類的定義就像是…

OSPF綜合實驗報告冊

一、實驗拓撲二、實驗要求1、R4為ISP&#xff0c;其上只配置IP地址&#xff1b;R4與其他所直連設備間均使用公有IP&#xff1b; 2、R3-R5、R6、R7為MGRE環境&#xff0c;R3為中心站點&#xff1b; 3、整個OSPF環境IP基于172.16.0.0/16劃分&#xff1b;除了R12有兩個環回&#x…

網絡層6——內部網關協議RIP、OSPF(重點)

目錄 一、基本概念 1、理想的路由算法應具備的特點 2、分層次的路由選擇協議 二、內部網關協議RIP 1、特點 2、路由交換信息 3、距離向量算法 4、壞消息傳送慢問題 5、RIP報文格式 三、內部網關協議OSPF 1、特點 2、其他特點 3、自治系統區域劃分 4、OSPF的5中分…

同品牌的系列廣告要如何保證宣傳的連貫性?

對于品牌的系列廣告而言&#xff0c;內容的連貫性十分重要。如果系列廣告之間缺乏內在聯系&#xff0c;不僅會削弱品牌形象的統一性&#xff0c;還可能導致用戶的認知混亂。保證宣傳內容的連貫性不是讓每則廣告完全相同&#xff0c;而是在變化中保持核心要素的一致性。我們該如…

深度學習:激活函數Activaton Function

一、為什么需要激活函數&#xff1f;神經網絡本質上是多個線性變換&#xff08;矩陣乘法&#xff09;疊加。如果沒有激活函數&#xff0c;即使疊加多層&#xff0c;整體仍等價于一個線性函數&#xff1a;這樣的網絡無法學習和擬合現實世界中復雜的非線性關系。激活函數的作用&a…

deepseek: 切分類和長函數到同名文件中

import re import sys import os import ast from tokenize import generate_tokens, COMMENT, STRING, NL, INDENT, DEDENT import iodef extract_entities(filename):"""提取類和函數到單獨文件"""with open(filename, r, encodingutf-8) as f…

新型融合肽遞送外泌體修飾可注射溫敏水凝膠用于骨再生

溫敏水凝膠因能模擬細胞外基質微環境&#xff0c;且具有原位注射性和形態適應性&#xff0c;在骨組織工程中應用廣泛。小腸黏膜下層&#xff08;SIS&#xff09;作為天然細胞外基質來源&#xff0c;富含 I 型和 III 型膠原蛋白及多種生物活性因子&#xff0c;其制備的水凝膠在組…

SPI接口的4種模式(根據時鐘極性和時鐘相位)

SPI&#xff08;Serial Peripheral Interface&#xff09; 接口根據時鐘極性&#xff08;CPOL&#xff09;和時鐘相位&#xff08;CPHA&#xff09;的不同組合&#xff0c;共有 4種工作模式。這些模式決定了數據采樣和傳輸的時序關系&#xff0c;是SPI通信中必須正確配置的關鍵…