This is a poorly written loop. C design model is that if it is not critical, we don't care, and if it is, the programmer should fix it so optimization can work. https://gcc.godbolt.org/z/ErMP4cn6s
This is a poorly written loop. C design model is that if it is not critical, we don't care, and if it is, the programmer should fix it so optimization can work. https://gcc.godbolt.org/z/ErMP4cn6s
void foo(int offset, int *arr) {
for(int i = offset; i < (offset + 16); i++) {
arr[i] = i + 32;
}
}
If you call this with offset = 100, the arr[i] in the loop will write to arr[100], arr[101], ..., arr[115]. void bar(unsigned int offset, int *arr) {
if(offset+16 < offset)fail();
for(size_t i = 0; i < 16; i++) {
arr[i] = i+ offset + 32;
}
}
If you call this with offset = 100, the arr[i] in the loop will write to arr[0], arr[1], ..., arr[15]. if (offset >= INT_MAX - 16) fail();
in foo()?(I mean, besides the fact that the size of the buffer pointed to by arr is highly unlikely to agree exactly with either INT_MAX or UNIT_MAX.)
That is precisely how it works already. The reason your code has no bounds checks is exactly because the compiler can assume that you have done your part and ensured that all indices are in bounds. This is what "the compiler can ignore UB" is all about.
The signed integer kerfuffle is just the same: The compiler assumes your cooperation in ensuring, beforehand, that your signed arithmetic never overflows. Its part of the bargain is generating the best possible code it can. Another part of its bargain is offering you the -fwrapv flag to communicate more about your expectations. A third part of the bargain is offering you sanitizers that can inform you that you have done something you probably didn't want.