C find static array size (preventing mistakes) [duplicate]

你说的曾经没有我的故事 提交于 2019-12-03 05:33:17

Try this:

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

It is not portable, but works with both gcc and clang and has fewer side effects than n.m.'s proposal.

This is what I use, with a solution for both C and C++.

It was a requirement for me that both work even on VLAs.

#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 <bool constant>
struct is_an_array
{
    /// Used when a constant sized (non-VLA) object is passed in
    /// only allow arrays past
    template<class B, size_t n>
    static _true_ test( B(&)[n] );
};

template <>
struct is_an_array<false>
{
    /// This happens only for VLAs; force decay to a pointer to let it work with templates
    template <class B>
    static _true_ test(B *n);
};

# define ARRAY_SIZEOF(arr) ({ typedef decltype(is_an_array<static_cast<bool>(__builtin_constant_p(sizeof(arr)))>::test(arr)) type; sizeof(arr) / sizeof((arr)[0]); })
#endif

Do you really need a compile-time assertion? If yes, I'm afraid there's no portable way, you can only get this to work on Clang and GCC, or some other compiler, with implementation-specific tricks.

But if you decide to go for portability, you can use a run-time error (which can be just as effective, depending on your testing strategy). Suppose you have an error-reporting function void error(char *errorText). The macro could look something like this (untested, but I hope you get the idea):

#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

This macro works (in my tests anyway) for clang and gcc. I'm almost sure there's no portable solution.

#define ARRAY_SIZE(a) \
    (({ static __typeof__(a) _aa; \
        static __typeof__(&(a)[0]) _pa = _aa; (void)_pa; }), \
           sizeof(a)/sizeof((a)[0]))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!