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.
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.
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.
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!
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.