Michael Haggerty <[email protected]> writes:
> If you pass a newly-initialized or newly-cleared `string_list` to
> `for_each_string_list_item()`, then the latter does
>
> for (
> item = (list)->items; /* note, this is NULL */
> item < (list)->items + (list)->nr; /* note: NULL + 0 */
> ++item)
>
> Even though this probably works almost everywhere, it is undefined
> behavior, and it could plausibly cause highly-optimizing compilers to
> misbehave.
> ...
> It would be a pain to have to change the signature of this macro, and
> we'd prefer not to add overhead to each iteration of the loop. So
> instead, whenever `list->items` is NULL, initialize `item` to point at
> a dummy `string_list_item` created for the purpose.
> ...
> -#define for_each_string_list_item(item,list) \
> - for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
> +extern struct string_list_item dummy_string_list_item;
> +#define for_each_string_list_item(item,list)
> \
> + for (item = (list)->items ? (list)->items : &dummy_string_list_item; \
> + item < (list)->items + (list)->nr; \
> + ++item)
Sorry, but I am confused.
So when (list)->items is NULL, the loop termination condition that
used to be
NULL < NULL + 0
that was problematic because NULL + 0 is problematic now becomes
&dummy < NULL + 0
in the new code? What made NULL + 0 not problematic now?