# Introduction

Array size macros in C++ are typically ported from C, and so often end up looking something like this.

``````#define ARRAY_SIZE_UNSAFE(A) (sizeof(A)/sizeof(*(A)))
``````

This will work, however it has no type safety, so you can pass it both an array or a pointer to an array.

This post shows how templates can be used in C++ to create a safer array size macro (this is the same technique that _countof uses in MSVC).

# The Code

The test case for our array size macro is shown below. The first usage should compile and produce the correct result (as a compile time constant), the second usage should fail to compile.

``````const int arr[] = { 0, 1, 2, 3, 4 };
const int *const ptrToArr = arr;

ARRAY_SIZE(arr);
ARRAY_SIZE(ptrToArr);
``````

The implementation of `ARRAY_SIZE` is as follows.

``````#define ARRAY_SIZE(A) (sizeof(ArraySizeHelper(A)))

template <typename T, size_t N>
char (&ArraySizeHelper(T (&a)[N]))[N];
``````

I’ll admit that the syntax looks like a confusing mess, so let’s break it down a bit.

• `ArraySizeHelper` is a function declaration (it doesn’t need a definition), which takes a reference to any type of array; in my test case above, “T” would be “int”, and “N” would be 5.
• The return type of `ArraySizeHelper` is a reference to an array of type “char” the same size as the array passed into the function; in my test case, this produces a return value of “char“.
• The `ARRAY_SIZE` macro then takes the size of the return type of the function (which is a compile time constant); “sizeof(char)” is 5, which is the correct size for my array.

While this may seem like overkill just to get the size of an array, the bonus is that as ArraySizeHelper only accepts a reference to an array, trying to pass “ptrToArr” produces a compiler error, which is exactly the behaviour we want.

A much more detailed explanation of how this function works is available on the MSDN blog.
{"ft_lang_label":"__label__en","ft_lang_prob":0.8238932,"math_prob":0.89628446,"size":1881,"snap":"2023-40-2023-50","text_gpt3_token_len":464,"char_repetition_ratio":0.11454449,"word_repetition_ratio":0.0,"special_character_ratio":0.24455076,"punctuation_ratio":0.10215054,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.98528725,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-09-26T05:28:14Z\",\"WARC-Record-ID\":\"<urn:uuid:e2a429fb-3108-4f1d-912b-9a327894df7e>\",\"Content-Length\":\"9251\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:ad072b84-84d9-4a5d-afa1-377c4afbd6e6>\",\"WARC-Concurrent-To\":\"<urn:uuid:091f252c-b135-4880-a4ef-ad2b457591ab>\",\"WARC-IP-Address\":\"217.194.210.85\",\"WARC-Target-URI\":\"https://tweex.net/post/c-a-safer-array-size-macro/\",\"WARC-Payload-Digest\":\"sha1:MDLKVTZAYQUK6TM4RYMLFTGRNOMYWUIO\",\"WARC-Block-Digest\":\"sha1:SCITZXD25W7UHPAHGKS6ZH7OH64IWJIM\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-40/CC-MAIN-2023-40_segments_1695233510149.21_warc_CC-MAIN-20230926043538-20230926073538-00873.warc.gz\"}"}