Quote Originally Posted by aghast View Post
Don't worry about it.

Calling code should be bounds checked by correct construction, not by adding checks:

for (int i = 0; i < length(array); ++i)

This avoids the need for any kind of additional checking, and guarantees that your code will never find any problems.

So why would you add checks? In case the caller does something stupid and fails to construct valid accesses.

That's a programming error, and deserves to be caught and reported as soon as possible.

Therefore, you want to have the checks in the low-level code. You want them to do something drastic, like ending the program.

So, what about performance costs? Well, make them cheap! If you're comparing a number in one register with a number in another register, that's cheap. If the "length" of your array is a stored value (not dynamically computed each time), and you're continually re-loading it, then it's in cache and doesn't cost any cycles (except the first one).

Thus, you need to make sure that the checks you do are against stored values, and are fast in the no-error case. (In the error case, you're going to kill the program, so take all the time you want!)

I'd say something like:

#define array_at(ARR, IDX) ((ARR)->ar_data[(IDX) < (ARR)->ar_length ? (IDX) : array_bounds_error((ARR), (IDX))])
Thanks! You're right though, I should just embed it at the lowest level. But I probably will make it opt-in rather than opt-out. That way, the user can decide for themselves which way to go. Most will probably turn it on for debugging and off for release builds.