__attribute__ ((attribute-list))
// 雙下劃線前後,雙括號包裹屬性列表,多屬性逗號分隔
GCC/Clang 擴展,提供編譯器優化提示、檢查增強、ABI 控制等能力。MSVC 不支持,需條件編譯隔離。
// 類 printf 檢查:第 1 參數為格式串,第 2 參數起檢查
extern void my_log(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
// 類 scanf 檢查
extern void my_scan(const char *fmt, ...) __attribute__((format(scanf, 1, 2)));
// 成員函數:隱含 this 指針佔第 1 參數,故從 2、3 開始
struct Logger {
void log(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
};
編譯器會對調用處參數與格式串匹配性報警 (需 -Wall),極大減少 printf("%s", 123) 類 Bug。
void abort(void) __attribute__((noreturn));
void exit(int) __attribute__((noreturn));
void my_fatal(const char *msg) __attribute__((noreturn));
// 用法:避免「控制路徑到達非 void 函數末尾」警告
int foo(int x) {
if (x < 0) my_fatal("負值");
return x * 2; // 編譯器知 my_fatal 不返回,無警告
}
| 屬性 | 語義 | 適用場景 |
|---|---|---|
| const | 純函數:無副作用,返回值僅依賴參數,不讀全局內存 | 數學函數、哈希、校驗和 |
| pure | 純函數:無副作用,返回值依賴參數和全局內存 | 只讀全局配置的查詢函數 |
int square(int x) __attribute__((const));
int get_config(int key) __attribute__((pure)); // 讀只讀全局配置
// 優化效果:循環中重複調用同參數 → 單次調用 + 緩存結果
for (int i = 0; i < 100; i++) total += square(5); // 只調用 1 次 square(5)
void my_init(void) __attribute__((constructor));
void my_fini(void) __attribute__((destructor));
// my_init 在 main 之前自動調用 (優先級可指定: constructor(101))
// my_fini 在 main 返回或 exit() 後自動調用
// 用途:庫自動註冊、環境初始化、檢測工具注入
| 屬性 | 作用 |
|---|---|
| malloc | 返回非空、不重疊指針,優化別名分析 |
| alloc_size(n) | 第 n 參數為分配大小,優化檢查 |
| nonnull(n...) | 指定參數不可為 NULL,空指針檢查 |
| returns_nonnull | 返回值非 NULL |
| warn_unused_result | 忽略返回值報警 |
| deprecated | 調用處報警棄用 |
| alias("name") | 創建別名符號 |
| visibility("hidden") | 符號不導出動態庫 |
// 對齊:強制 32 位元組對齊 (利於 SIMD、緩存行)
int buffer[1024] __attribute__((aligned(32)));
// 緊湊:最小對齊 (結構體無填充)
struct Packed { char c; int i; } __attribute__((packed)) p;
// 未使用變量不警告
int debug_unused __attribute__((unused));
// 棄用變量
int old_api __attribute__((deprecated("用 new_api")));
// 段屬性:放入特定段
char firmware_data[] __attribute__((section(".firmware"))) = "...";
// 線程局部存儲
__thread int tls_var __attribute__((tls_model("initial-exec")));
// 結構體對齊
struct Aligned8 { short a; char b; } __attribute__((aligned(8)));
// sizeof = 8 (非對齊為 4)
// 透明聯合:參數可直接傳遞聯合成員類型
typedef union { int i; float f; } __attribute__((transparent_union)) IntFloat;
void func(IntFloat u); // 可傳 int 或 float,自動轉換
// 向量類型 (SIMD)
typedef int v4si __attribute__((vector_size(16))); // 4 x int
v4si a = {1,2,3,4}, b = {5,6,7,8};
v4si c = a + b; // {6,8,10,12} 向量化運算
// 寫法 1: 多個 __attribute__
void func(void) __attribute__((noreturn)) __attribute__((format(printf,1,2)));
// 寫法 2: 單個 __attribute__ 多屬性
void func(void) __attribute__((noreturn, format(printf,1,2)));
// 跨編譯器兼容:非 GNU 定義為空
#ifndef __GNUC__
#define __attribute__(x) /* nothing */
#endif
// 標準庫風格使用
#if defined(__GNUC__) || defined(__clang__)
#define ATTR_NORETURN __attribute__((noreturn))
#define ATTR_FORMAT(fmt, first) __attribute__((format(printf, fmt, first)))
#else
#define ATTR_NORETURN
#define ATTR_FORMAT(fmt, first)
#endif
void die(const char *fmt, ...) ATTR_NORETURN ATTR_FORMAT(1,2);
#include <string.h>
#include <stdarg.h>
// 返回值非 NULL、參數 1/2 非 NULL、格式串檢查、棄用警告
char *safe_strcpy(char *dest, const char *src)
__attribute__((returns_nonnull, nonnull(1,2), warn_unused_result));
char *safe_strcpy(char *dest, const char *src) {
return strcpy(dest, src); // 實際應用用 strlcpy/strncpy_s
}
// 格式化輸出封裝
void log_info(const char *fmt, ...)
__attribute__((format(printf, 1, 2)));
void log_info(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
// 測試
int main() {
char buf[100];
safe_strcpy(buf, "hello"); // 正常
// safe_strcpy(NULL, "x"); // 編譯警告: null argument
log_info("數值: %d", 42); // 正常
// log_info("數值: %s", 42); // 編譯警告: format '%s' expects 'char*'
return 0;
}
# GCC
gcc --target-help | grep attribute
# Clang
clang -cc1 -fsyntax-only --help | grep attribute
# 官方文檔
# https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
# https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
# https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html