If you want to use undefined behavior to elide the NULL checks, consider:
int computation(int *a, int *b) {
if(a == NULL && b == NULL) return 0;
if(a == NULL) return *b;
if(b == NULL) return *a;
return ...something with *a and *b...;
}
...elsewhere...
int *a = malloc(sizeof(*a) * 1024);
int *b = malloc(sizeof(*a) * 1024);
for(int i = 0; i < 1024; i++) {
a[i] = i;
b[i] = i * 2;
}
int c[1024];
for(int i = 0; i < 1024; i++)
c = computation(a + i, b + i);
The compiler is allowed to remove the NULL checks from an inlined computation here, since the code already dereferenced a and b in the initialization step. Failing to do so would make the code a lot slower, and this optimization seems completely reasonable to me.My pet one of these is "this (by which I mean the pointer of the current object, not the demonstrative pronoun ;P) cannot be NULL". clang has started outputting messages to me that it will soon stop honoring my checks that this is not NULL, entirely removing them from my code, even in cases where this actually can be NULL and the code is not guaranteed to crash in some predictable way. If the language helped me guarantee that this was never NULL, that would be one thing, but it doesn't, and the compiler has decided, for reasons I don't understand, to remove one of the only mechanisms I currently have to detect, log, and mitigate.
References are a similar thing: it would be one thing if dereferencing a NULL pointer caused my program to crash, so clearly the NULL checks on the address of a reference are not useful. But it doesn't work like that. Dereferencing a NULL pointer returns a NULL reference that doesn't cause a crash until the pointer is used. This is actually kind of similar to weakly-linked symbols, where a declared function can have its address be NULL. This is a feature of linkers and the compiler and puts people in a regime where it sometimes makes a lot of sense to compare the address of an expression with NULL.
But somehow, this one is special; so special that even though the compiler knew what I wanted so clearly it felt the need to spit out a paragraph of nonsense at me to tell me that I should remove this check, and that it really didn't want this check in my code in the first place, if I was stupid enough to leave it in my code it was going to delete it for me. I just... I don't understand how that is even remotely reasonable behavior. If it was a side effect of the optimizer and there was no way to surmise what I wanted, then that would be one thing: but the compiler is detecting my code, and demanding that either I remove it myself or it will take control? WTF.