Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

A word of caution to anyone writing C macros like the examples in the article... There is a potential error in this macro:

  #define COUNTOF(array) \
      (sizeof(array) / sizeof(array[0]))
Generally, when you write a C macro, you should parenthesize each use of any argument inside the macro. The exceptions would be cases like token pasting where you want the literal argument text and only the text.

I don't have a specific failure example in mind for the COUNTOF macro (maybe someone can post one?) - but here is a macro where it is easy to see the problem:

  #define TIMESTWO( value )  ( value * 2 )

  int ShouldBeEight = TIMESTWO( 2 + 2 );  // Oops, it's 6!
This happens because the macro call expands to:

  2 + 2 * 2
Parentheses prevent this problem:

  #define TIMESTWO( value )  ( (value) * 2 )
The macro also illustrates a common misconception: sizeof is not a macro or function call, it's an operator. So wrapping the argument to sizeof in parens isn't necessary unless they are needed for other reasons. (They don't hurt anything, they just aren't needed.)

So when I've written a COUNTOF macro (and it is a very handy macro in C/C++ code if your compiler doesn't already provide a similar one like __countof in MSVC), I write it like this:

  #define COUNTOF( array )  \
      ( sizeof (array) / sizeof (array)[0] )
The space after each sizeof is my attempt to indicate that the following parens are not function/macro call parens, but are there specifically to wrap the array argument safely.


You also shouldn’t repeat the argument: “while(COUNTOF(ptr++) > 0) { }” would do horrible things (if it compiles; didn’t check) for example.

There are various preprocessor tricks to avoid this stuff (eg “do{ x = (array); ... } while (0)”), but, honestly, if you want this sort of memory safety, C++ is your friend.


sizeof doesn't actually evaluate the expression, so in this case ptr++ won't get evaluated at all (nevermind twice). Good thing to be aware of in general though.


Even plain `COUNTOF(ptr)` is wrong, unless `ptr` is an array.


    -Werror-sizeof-pointer-div
Or in C++:

    #include <type_traits>

    template < typename T, std::size_t N >
    constexpr std::size_t count_of(const T (&)[N]) { return N; }

    #define COUNTOF(a) std::integral_constant<std::size_t, count_of(a)>::value
(C++03 friendly versions are entirely possible, but left as an exercise to the reader)


Agreed, although I don't know of a straight C way of implementing COUNTOF without repeating the argument. So it becomes a lesser-of-two-evils question: is the macro (with its flaws) better than doing the calculation explicitly every time you need it?

The __countof macro in MSVC does go to some extra work to make it more safe, so it's definitely recommended to use that instead of rolling your own COUNTOF in that environment.


sizeof does not perform evaluation of its argument in the traditional sense, so this is not an issue here.


Ah yes, thanks for the reminder. This is also the reason why COUNTOF is valid for a zero-length array.

Even though array[0] is non-existent in this case, it's fine to pass it to sizeof to get the size of an array element as if there were one. After all, a pointer can point one element past the end of an array.


> After all, a pointer can point one element past the end of an array.

Hmm, I wouldn’t put it that way, since sizeof(array[1]) would work just as well. I like to think of sizeof running the type checker on the expression provided and then looking up the size of the type of the expression: this makes it clear that the thing inside can be completely bogus as long as it is syntactically correct.


That is a much better way to look at it, thanks!


Subexpressions with side effects being passed to macros is a great way of having the side effect occur repeatedly through repeated evaluation of the operands to the macro. Be careful!


Also, I've seen a buggy linux kernel driver use the above macro, then pass it a pointer. Only caught it because -Wsizeof-pointer-div in a recent compiler.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: