45

I've seen several macros for array length floating around:

From this question:

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array) / (sizeof(type))

And Visual Studio's _countof:

#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))

What I'd like to know is:

  1. What's the difference between those using array[0] and *array?
  2. Why should either be preferred?
  3. Do they differ in C++?
0

3 Answers 3

83

Here's a better C version (from Google's Chromium project):

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

It improves on the array[0] or *array version by using 0[array], which is equivalent to array[0] on plain arrays, but will fail to compile if array happens to be a C++ type that overloads operator[]().

The division causes a divide-by-zero operation (that should be caught at compile time since it's a compile-time constant expression) for many (but not all) situations where a pointer is passed as the array parameter.

See Is there a standard function in C that would return the length of an array? for more details.

There's a better option for C++ code. See Compile time sizeof_array without using a macro for details.

Sign up to request clarification or add additional context in comments.

7 Comments

That's incredibly cryptic just to guard against being used wrongly in C++, considering that something else should be used in C++ anyway.
You're right that this shouldn't be used in C++, but the bit that provides some safety specifically for C++ isn't really too cryptic (it's just the unusual indexing). The really cryptic part guards against some types of misuse in C that is actually pretty hard to guard against (and the macro doesn't even perfect guard against this misuse). The misuse it guards against (passing a pointer instead of an array argument) occurs often enough that it pays to have the complexity. Wrapped up in a macro, the complexity isn't too much of an issue (and this macro is less cryptic than many I come across).
What the hell type is 0[x]? You can do that?
@Matt: the [] operator is commutative (by virtue of it being defined in terms of pointer arithmetic). However that part of the macro is the less important 'safety' - I'm sorry that it seems to be getting the attention.
As noted in the linked source , the second half of this check only catches some cases. (In particular it doesn't catch x being a char *, which is a common use case)
|
18
  1. What's the difference between those using array[0] and *array?
  2. Why should either be preferred?
  3. Do they differ in C++?

(1) No difference in C. No difference for an actual raw array in C++.

(2) No technical grounds to prefer one or the other, but newbies might be confused by the pointer dereference.

(3) In C++ you would normally not use the macro, because it's very unsafe. If you pass in a pointer instead of an actual raw array, code will compile but yield incorrect result. So in C++ you would/should instead use a function template, like …

#include <stddef.h>

typedef ptrdiff_t Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }

This only accepts actual raw array as argument.

It's part of a triad of functions startOf, endOf and countOf that it's very convenient to define so that they can be applied to both raw arrays and standard library containers. As far as I know this triad was first identified by Dietmar Kuehl. In C++0x startOf and endOf will most probably be available as std::begin and std::end.

Cheers & hth.,

7 Comments

+1: Interesting! Is there a reason to use <stddef.h> rather than <cstddef>?
Not that I can think of; and I can think of several reasons to prefer <cstddef>.
For what little it's worth, here's my take on the <cstddef> vs. <stddef.h> reasoning (note: I prefer the old-fashioned C variation myself): stackoverflow.com/questions/2118422/…
I'm in the stddef.h even in C++ camp too. Trying to deprecate C standard library is ridiculous.
Worth noting that in general there is a difference between *a and a[0], which shows up when a is a pointer to an incomplete type. This doesn't influence the sizeof though, since in that case sizeof would be invalid anyway.
|
4

1) Nothing, the value of an array is a pointer to it's first element. So *array == array[0]
2) Personal Preference
3) No

Note that this macro wont work if called inside a function where the array is passed as a parameter into the function. This is because the array object passed "decays" into a pointer rather than a deep copy.

1 Comment

Yes, it may effectively work as sizeof(void*)/sizeof(array[0]), which - in contemporary reality - means 8, 4, 2, 1, or 0. ;) Anyway - nothing can help you in such a function at compile time - you can never know who calls it, and with how large an array.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.