Правильный ответ здесь заключается в том, что вы не должны были ожидать каких-либо отношений, заказов или иным образом.За исключением объединений, стандарт C не определяет линейное адресное пространство, в котором могут перекрываться объекты разных типов.Во многих комбинациях архитектура / компилятор-инструмент-цепочка имеет место случайное совпадение, но вы никогда не должны полагаться на них.Тот факт, что приведение указателя к подходящему скалярному типу дает число, сравнимое с другими значениями того же типа, никоим образом не подразумевает, что число является каким-либо конкретным адресом памяти.
Итак:
int* p;
int z = 3;
int* pz = &z;
size_t cookie = (size_t)pz;
p = (int*)cookie;
printf("%d", *p); // Prints 3.
Работает, потому что стандарт говорит, что он должен работать, когда cookie
получен из того же типа указателя, в который он конвертируется.Преобразование в любой другой тип является неопределенным поведением.Указатели не представляют память, они ссылаются на «хранилище» в аннотации.Они являются просто ссылками на объекты или NULL, и стандарт определяет, как должны вести себя указатели на один и тот же объект и как их можно преобразовать в скалярные значения и обратно.
Дано:
char array[5] = "five";
Стандарт гласит, что &(array[0]) < &(array[1])
и (&(array[0])) + 1) == &(array[1])
, но при этом не учитывается порядок элементов в array
в памяти.Авторы компилятора могут свободно использовать любые машинные коды и схемы памяти, которые они считают подходящими для целевой архитектуры.
В случае объединения, которое предусматривает некоторое перекрытие объектов в хранилище, стандарт только говорит, чтокаждое из его полей должно быть соответствующим образом выровнено для их типов, но почти все остальное в них определяется реализацией.Ключевое предложение: 6.2.6.1 p7 :
Когда значение хранится в элементе объекта типа объединения, байты представления объекта, которые не соответствуютэтот член, но соответствует другим членам, принимает неопределенные значения.
Суть всего этого в том, что стандарт C определяет абстрактную машину.Компилятор генерирует архитектуру этой машины на основе вашего кода.Вы не можете понять абстрактную машину C с помощью простых эмпирических средств, потому что детали реализации стекаются в ваш набор данных.Вы должны ограничить свои наблюдения теми, которые имеют отношение к абстракции.Следовательно, избегайте неопределенного поведения и очень внимательно относитесь к поведению, определяемому реализацией.