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])) 

它不是便携式的,但与gccclang ,副作用比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]))