编译时区分变长数组(VLA)与普通数组的实现方案问询
编译时区分普通数组与变长数组(VLA)的实现方案
针对你的需求,我们可以扩展原有的IS_ARRAY宏,实现**编译时判断表达式是否为变长数组(VLA)**的宏,从而在SWAP()中加入静态断言,提前给出友好提示。
核心宏实现
// 判断是否为数组(原宏保留) #define IS_ARRAY(T) \ _Generic( &(T), \ typeof(*T) (*)[] : 1, \ default : 0 \ ) // 判断是否为普通固定大小数组 #define IS_FIXED_ARRAY(T) \ _Generic( &(T), \ typeof(*T) (*)[sizeof(T)/sizeof(*T)] : 1, \ default : 0 \ ) // 判断是否为变长数组(VLA):是数组但不是固定大小数组 #define IS_VLA(T) (IS_ARRAY(T) && !IS_FIXED_ARRAY(T))
集成到SWAP宏中
修改你的SWAP()宏,加入对VLA的静态断言检查,当传入VLA时直接触发编译错误并给出引导信息:
#include <string.h> /** * 可用于表达式中的静态断言,类似C11 _Static_assert() * 表达式为假时输出错误信息MSG,始终返回1 */ #define STATIC_ASSERT_EXPR(EXPR, MSG) \ (!!sizeof( struct { static_assert ( (EXPR), MSG ); char c; } )) /** * 判断表达式X与类型T是否兼容 * 兼容返回1,否则返回0 */ #define IS_COMPATIBLE(X, T) \ _Generic((X), \ T: 1, \ default: 0) [[gnu::always_inline]] static inline void swap_internal(size_t psize, void *restrict tmp, void *restrict p1, void *restrict p2) { memcpy(tmp, p1, psize); memcpy(p1, p2, psize); memcpy(p2, tmp, psize); } // 判断是否为数组(原宏保留) #define IS_ARRAY(T) \ _Generic( &(T), \ typeof(*T) (*)[] : 1, \ default : 0 \ ) // 判断是否为普通固定大小数组 #define IS_FIXED_ARRAY(T) \ _Generic( &(T), \ typeof(*T) (*)[sizeof(T)/sizeof(*T)] : 1, \ default : 0 \ ) // 判断是否为变长数组(VLA) #define IS_VLA(T) (IS_ARRAY(T) && !IS_FIXED_ARRAY(T)) /** * 交换A和B的内容,不支持VLA * 传入VLA时会触发编译断言,引导使用适配VLA的版本 */ #define SWAP(A, B) \ swap_internal( \ (sizeof (A) * STATIC_ASSERT_EXPR( sizeof (A) == sizeof (B), \ #A " and " #B " must have same size.")), \ (char [ STATIC_ASSERT_EXPR( IS_COMPATIBLE(A, typeof(B)), \ #A " and " #B " must have compatible types") * \ STATIC_ASSERT_EXPR( !IS_VLA(A) && !IS_VLA(B), \ #A " or " #B " is a variable-length array (VLA). Use VLA-compatible SWAP variant instead.") * \ sizeof (A)] {}), \ &(A), \ &(B))
原理说明
- 普通固定大小数组的类型是完整类型,编译时可以确定其大小,因此
&T的类型可以匹配typeof(*T)(*)[N](N是编译时已知的固定值)。 - 变长数组(VLA)的大小由运行时表达式决定,编译时无法确定固定大小,因此
&T的类型只能匹配通用的数组指针类型typeof(*T)(*)[],无法匹配带固定长度的数组指针,从而被IS_FIXED_ARRAY排除,最终IS_VLA返回真。
这样修改后,当用户向SWAP()传入VLA时,编译器会直接输出你定义的友好提示,而不是默认的复合字面量错误,引导用户切换到适配VLA的交换宏。
内容的提问来源于stack exchange,提问作者Madagascar
相关产品推荐
相关产品推荐

