Стандарт C гарантирует, что size_t - это тип, который может содержать любой индекс массива. Это означает, что логически size_t должен содержать любой тип указателя. Я читал на некоторых сайтах, которые я нашел в Googles, что это законно и/или всегда должно работать:
void *v = malloc(10);
size_t s = (size_t) v;
Итак, затем на C99 в стандарте введены типы intptr_t и uintptr_t, которые являются подписанными и неподписанными типами, гарантированными для хранения указателей:
uintptr_t p = (size_t) v;
В чем разница между использованием size_t и uintptr_t? Оба являются неподписанными, и оба должны иметь возможность удерживать любой тип указателя, поэтому они кажутся функционально идентичными. Есть ли какая-то реальная веская причина использовать uintptr_t (или еще лучше, a void *), а не size_t, кроме ясности? В непрозрачной структуре, где поле будет обрабатываться только внутренними функциями, есть ли причина не делать этого?
Точно так же ptrdiff_t был подписанным типом, способным удерживать различия указателя и, следовательно, способным удерживать большинство указателей, так как он отличается от intptr_t?
Разве не все эти типы в основном обслуживают тривиально разные версии одной и той же функции? Если нет, то почему? Что я не могу сделать с одним из них, с которым я не могу справиться? Если да, то почему C99 добавили два языка, которые были бы лишними к языку?
Я готов игнорировать указатели на функции, поскольку они не применяются к текущей проблеме, но не стесняйтесь упоминать их, поскольку у меня есть скрытое подозрение, что они будут иметь центральное значение для "правильного" ответа.