C找到静态数组大小(防止错误)
查找静态数组的大小是一种常见操作。 参见: C找到静态数组大小 – sizeof(a) / sizeof((a)[0])
这可以包装成一个宏,例如:
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
但是它可能会意外地传入常规指针。
例如: void func(SomeArray **foo) { int i = ARRAY_SIZE(foo); }
void func(SomeArray **foo) { int i = ARRAY_SIZE(foo); }
虽然它的有效C,但往往最终成为一个逻辑错误。
它可以防止这种错误(利用每个处理器在零长度位字段上失败) 。
#define ARRAY_SIZE(a) \ ((sizeof(struct { int isnt_array : \ ((const void *)&(a) == &(a)[0]); }) * 0) + \ (sizeof(a) / sizeof(*(a))))
我发现这个宏适用于GCC,但是对于间接引用的成员,它与Clang失败了。 有error: expression is not an integer constant expression
例如:
-
char word[8]; int i = ARRAY_SIZE(word);
好。 -
struct Bar { word[8]; }
void func(struct Bar *foo) { int i = ARRAY_SIZE(foo->word); }
失败了。
有没有更便携的方式来实现这个? (与Clang合作当然很好,虽然我对一般的可移植性感兴趣……其他编译器也是如此)。
这似乎是一项普遍的任务,拥有一个可重复使用的便携式宏将是一件好事。
试试这个:
#define ASSERT_ARRAY(a) \ sizeof(char[1-2*__builtin_types_compatible_p(__typeof__(a), __typeof__(&(a)[0]))]) #define ARRAY_SIZE(a) \ (ASSERT_ARRAY(a)*0 + sizeof(a)/sizeof((a)[0]))
它不是便携式的,但与gcc
和clang
,副作用比nm的提议少。
这就是我使用的,它提供了C和C ++的解决方案。
对我来说,两者都要在VGA上工作。
#ifndef __cplusplus int _ptr_used_(void) __attribute__((error("Pointer used in place of array") )); #define ARRAY_SIZEOF(arr) ( \ __builtin_types_compatible_p(typeof(arr), typeof((arr)[0])*) \ ? _ptr_used_() \ : sizeof(arr)/sizeof((arr)[0]) \ ) #else /// A type that exists struct _true_ {}; template struct is_an_array { /// Used when a constant sized (non-VLA) object is passed in /// only allow arrays past template static _true_ test( B(&)[n] ); }; template <> struct is_an_array { /// This happens only for VLAs; force decay to a pointer to let it work with templates template static _true_ test(B *n); }; # define ARRAY_SIZEOF(arr) ({ typedef decltype(is_an_array(__builtin_constant_p(sizeof(arr)))>::test(arr)) type; sizeof(arr) / sizeof((arr)[0]); }) #endif
你真的需要一个编译时断言吗? 如果是的话,我担心没有可移植的方法,你只能通过特定于实现的技巧将它用于Clang和GCC或其他编译器。
但是如果您决定寻求可移植性,则可以使用运行时错误(这可能同样有效,具体取决于您的测试策略)。 假设您有一个错误报告函数void error(char *errorText)
。 宏可能看起来像这样(未经测试,但我希望你能得到这个想法):
#ifdef DEBUG /* Place your debug-mode-flag macro here. You won't want the extra branch in the release build */ #define ARRAY_SIZE(a) \ ((const void *)&(a) == &(a)[0]) ? \ (sizeof(a) / sizeof(*(a))) : (error("Tried to treat pointer as array!"), 0) #else #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #endif
对于clang和gcc,这个宏(无论如何我的测试)都有效。 我几乎可以肯定没有便携式解决方案。
#define ARRAY_SIZE(a) \ (({ static __typeof__(a) _aa; \ static __typeof__(&(a)[0]) _pa = _aa; (void)_pa; }), \ sizeof(a)/sizeof((a)[0]))