Какой из следующих способов лечения и попытки восстановления C-указателя гарантированно будет действительным?
1) Отбрасывать указатель void и назад
int f(int *a) {
void *b = a;
a = b;
return *a;
}
2) Приведение в нужный размер и обратно
int f(int *a) {
uintptr_t b = a;
a = (int *)b;
return *a;
}
3) Несколько тривиальных целых операций
int f(int *a) {
uintptr_t b = a;
b += 99;
b -= 99;
a = (int *)b;
return *a;
}
4) Целочисленные операции, нетривиальные, чтобы затушевать провенанс, но которые тем не менее оставят неизменным значение
int f(int *a) {
uintptr_t b = a;
char s[32];
// assume %lu is suitable
sprintf(s, "%lu", b);
b = strtoul(s);
a = (int *)b;
return *a;
}
5) Больше косвенных целых операций, которые оставят неизменным значение
int f(int *a) {
uintptr_t b = a;
for (uintptr_t i = 0;; i++)
if (i == b) {
a = (int *)i;
return *a;
}
}
Очевидно, что случай 1 действителен, и случай 2 тоже должен быть. С другой стороны, я наткнулся на сообщение Криса Лэттнера, которого я, к сожалению, сейчас не могу найти, - что-то похожее на случай 5 недействительно, что стандарт лицензирует компилятор, чтобы просто скомпилировать его в бесконечный цикл. Тем не менее каждый случай выглядит как неочевидное расширение предыдущего.
Где линия, заключенная между действительным случаем и недопустимым?
Добавлен на основе обсуждения в комментариях: пока я до сих пор не могу найти сообщение, которое вдохновило случай 5, я не помню, какой тип указателя был задействован; в частности, это мог быть указатель на функцию, и именно поэтому этот случай продемонстрировал неверный код, тогда как мой случай 5 является допустимым кодом.
Второе дополнение: хорошо, вот еще один источник, который говорит, что есть проблема, и у меня есть ссылка. https://www.cl.cam.ac.uk/~pes20/cerberus/notes30.pdf - обсуждение провенанса указателя - говорит и подтверждает доказательства, что нет, если компилятор теряет следы, где появился указатель from, it undefined.