GCC /Clang __attribute__
__attribute__ 系列(GCC / Clang)🛠️
__attribute__((...)) 是 GCC / Clang 提供的扩展,用来把额外的语义 / 优化提示告诉编译器。合理使用可以帮助编译器生成更高效或更安全的代码;滥用则可能导致代码臃肿、不可移植或难以调试。下面把常用属性按用途分类讲清楚:语法、常见属性、示例、注意事项与可移植写法。
1) 语法与现代替代写法
- 经典写法(C / C++):
int f(int) __attribute__((pure));
- 多属性:
int f(int) __attribute__((pure, hot));
- C++11 风格(部分属性支持):
[[gnu::pure]]
[[nodiscard]]
建议:对公共头文件,使用宏封装以便可移植到 MSVC 或兼容不同编译器版本。
2) 常用函数属性(按类别)
语义 / 副作用相关
-
pure
函数无副作用(除了读取内存)。返回值依赖参数 + 读取的内存。允许消除重复调用。int strcmp(const char*, const char*) __attribute__((pure)); -
const
更严格:函数仅依赖其参数(不能读取可变内存或全局)。更强的优化空间。int square(int) __attribute__((const));
内联 / 调用控制
-
always_inline/inline
尽量/强制内联(可能被编译器在某些情况下忽略)。static inline int add(int a,int b) __attribute__((always_inline)); -
noinline
禁止内联(对调试、大小控制有用)。void heavy_log(const char*) __attribute__((noinline));
性能 / 布局提示
-
hot/cold
告诉编译器热/冷函数,用于代码布局与优化策略(把 cold 放到.cold)。void handle_error() __attribute__((cold)); -
flatten
强制将函数中可内联的调用全部展开(可能导致代码暴涨)。 -
optimize("O3")
针对单函数设置优化级别(注意可读性与一致性问题)。
控制流与错误
-
noreturn
函数不会返回(例如exit()、abort()),帮助编译器消除后续死代码警告。void fatal_error(const char*) __attribute__((noreturn));
接口 / 参数校验
-
format(printf, fmt_idx, arg_idx)
告诉编译器这是 printf/scanf 风格函数,启用参数检查(位置从 1 开始)。void my_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -
sentinel
用于可变参数函数,检查尾部是否有 NULL 终结(常用于 varargs)。 -
nonnull
指定某些参数不应为 NULL(优化/警告提示)。void foo(char *p) __attribute__((nonnull(1)));
返回值 / 分配相关
returns_nonnull(或__attribute__((returns_nonnull)))
告诉编译器函数返回非 NULL 指针。malloc
返回的指针不与现存内存重叠(可用于更好优化)。
诊断 / 可用性
deprecated("msg")
标记废弃的接口(编译时发出警告,支持自定义消息)。error("msg")
直接把使用视为错误(GCC 有此属性)。unused/used
标记变量/函数避免被编译器误报未使用或确保不被删除。
连接 / 链接器相关
-
visibility("default"|"hidden"|"internal")
控制符号导出(对共享库非常重要,能减少动态符号表与重定位)。int api_fn() __attribute__((visibility("default"))); -
weak/alias("sym")
创建弱符号或为符号创建别名(高级用法)。
构造 / 析构(初始化)
-
constructor/destructor
使函数在main()之前或之后运行(像静态初始化)。void init_fn() __attribute__((constructor));
3) 变量 / 类型级属性
-
aligned(n)
设置类型或变量的对齐(影响 ABI、性能)。int x __attribute__((aligned(64))); struct S { char c; } __attribute__((aligned(8))); -
packed
去掉对齐填充(紧凑布局),注意可能导致未对齐访问与性能下降。struct __attribute__((packed)) P { char c; int i; }; -
transparent_union、may_alias等(高级)用于 ABI/兼容性技巧。 -
section("name")
将变量/函数放到指定段(用于嵌入式或特殊链接需求)。
4) 实例与常见用法(代码片段)
// printf-like checker
void my_log(const char *fmt, ...) __attribute__((format(printf, 1, 2)));// error handling (cold)
void handle_error(const char *msg) __attribute__((cold, noreturn));// performance hints
int compute(int x) __attribute__((hot, always_inline, const));// avoid inlining (keep stack trace)
void debug_breakpoint() __attribute__((noinline));// mark API exported, smaller dynamic symbol table
int public_api() __attribute__((visibility("default")));
5) 常见坑 / 注意事项
- 可移植性:这些是 GCC/Clang 扩展;MSVC 有不同语法(
__declspec)。请用宏封装并在不支持时回退为空定义。 - 改变 ABI:
packed、aligned会影响结构布局和 ABI,可能导致未定义行为或性能问题。 - 调试影响:
always_inline/flatten会把函数展开,导致堆栈帧信息丢失,影响调试与栈回溯。 - 代码膨胀:
flatten、always_inline可能导致二进制变大(instruction cache 受影响)。 - 误用导致性能变差:
pure/const仅在语义满足时使用;错误标注会让编译器做不安全的优化。 - 编译器支持差异:某些属性 Clang 支持但 GCC 不支持(反之亦然),可用
__has_attribute做条件编译(见下)。
6) 可移植的宏封装建议(示例)
把属性包装成宏,便于不同编译器兼容:
#pragma once/* ===========================================================* Cross-Compiler Attribute Macros* Compatible with GCC, Clang, and MSVC (fallback to empty)* =========================================================== */#if defined(__has_attribute)
# define HAS_ATTR(x) __has_attribute(x)
#else
# define HAS_ATTR(x) 0
#endif#if defined(_MSC_VER)
# define FORCE_INLINE __forceinline
# define NOINLINE __declspec(noinline)
# define DEPRECATED(msg) __declspec(deprecated(msg))
#else
# define FORCE_INLINE inline __attribute__((always_inline))
# define NOINLINE __attribute__((noinline))
# if HAS_ATTR(deprecated) || defined(__GNUC__)
# define DEPRECATED(msg) __attribute__((deprecated(msg)))
# else
# define DEPRECATED(msg)
# endif
#endif/* --- Function purity hints --- */
// Pure: no side effects, result depends only on args + memory reads
#if HAS_ATTR(pure) || defined(__GNUC__)
# define PURE __attribute__((pure))
#else
# define PURE
#endif// Const: stronger than pure, depends only on args (no memory access)
#if HAS_ATTR(const) || defined(__GNUC__)
# define CONST __attribute__((const))
#else
# define CONST
#endif/* --- Hot/Cold function hints --- */
#if HAS_ATTR(hot) || defined(__GNUC__)
# define HOT __attribute__((hot))
#else
# define HOT
#endif#if HAS_ATTR(cold) || defined(__GNUC__)
# define COLD __attribute__((cold))
#else
# define COLD
#endif/* --- Inline flattening --- */
#if HAS_ATTR(flatten) || defined(__GNUC__)
# define FLATTEN __attribute__((flatten))
#else
# define FLATTEN
#endif/* --- Function flow attributes --- */
// Function never returns
#if HAS_ATTR(noreturn) || defined(__GNUC__)
# define NORETURN __attribute__((noreturn))
#else
# define NORETURN
#endif// printf-style format checking
#if HAS_ATTR(format) || defined(__GNUC__)
# define FORMAT(archetype, fmt_idx, var_idx) \__attribute__((format(archetype, fmt_idx, var_idx)))
#else
# define FORMAT(archetype, fmt_idx, var_idx)
#endif/* --- Branch prediction hints --- */
#if defined(__GNUC__) || defined(__clang__)
# define LIKELY(x) __builtin_expect(!!(x), 1)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
#endif/* --- Prefetch hint --- */
#if defined(__GNUC__) || defined(__clang__)
# define PREFETCH(addr, rw, locality) __builtin_prefetch((addr), (rw), (locality))
#else
# define PREFETCH(addr, rw, locality) ((void)0)
#endif/* --- Variable/struct attributes --- */
// Force alignment
#if HAS_ATTR(aligned) || defined(__GNUC__)
# define ALIGNED(n) __attribute__((aligned(n)))
#else
# define ALIGNED(n)
#endif// Pack struct (no padding, ABI sensitive!)
#if HAS_ATTR(packed) || defined(__GNUC__)
# define PACKED __attribute__((packed))
#else
# define PACKED
#endif// Control symbol visibility (shared libs)
#if HAS_ATTR(visibility) || defined(__GNUC__)
# define EXPORT __attribute__((visibility("default")))
# define HIDDEN __attribute__((visibility("hidden")))
#else
# define EXPORT
# define HIDDEN
#endif
7) 测试与落地建议
- 先测量后优化:用
perf/ VTune / sampling profiler 找到热点,再用属性微调。 - 小步改动:一次只改一个热点,比较二进制大小、分支未命中和 cycles。
- 结合 PGO:Profile-Guided Optimization 可在很多情况下胜过手动注解。
- 记录兼容约束:在项目 README 记录哪些属性被使用、为何使用、对哪个编译器/平台有效。
8) (cheat-sheet)
pure/const— 无副作用 / 仅依赖参数format(printf, m, n)— printf/scanf 参数检查noreturn— 不返回always_inline/noinline— 控制内联hot/cold— 热/冷函数提示flatten— 全部展开(慎用)visibility("hidden")— 减少导出符号deprecated("msg")— 标记废弃packed/aligned(n)— 控制内存布局(影响 ABI)
