В чем разница между адресом указателя и значением int, преобразованным из указателя - PullRequest
1 голос
/ 02 июня 2019

Я думал, что адрес ptr и адрес a совпадают друг с другом. А также я подумал, что адрес ptr такой же, как и значение int, преобразованное из указателя.

Но результат консоли мне отказал. В чем причина? Как я могу понять результат.

#include <stdio.h>

int main() {
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *) ((int) a);

    printf("a's address: %p \n", a);
    printf("ptr's address: %p \n", ptr);
    printf("ptr's int value: %x", (int)ptr);

    return 0;
}

Результат консоли

a's address: 0x7ffee8d30600 
ptr's address: 0xffffffffe8d30600 
ptr's int value: e8d30600

пс

Я отредактировал заголовок, и оригинальный двусмысленный заголовок - «В чем разница между адресом указателя и значением int указателя»

Ответы [ 3 ]

1 голос
/ 02 июня 2019

Не совсем то, что вы пытаетесь достичь здесь.Int содержит только 32-битное значение.Таким образом, (int) ptr будет возвращать только 32-битное значение адреса ptr, которое является младшими 4 байтами, которые вы получаете.

1 голос
/ 02 июня 2019

C имеет тип uintptr_t, который позволяет хранить значение указателя:

void *p = …;
uintptr_t u = (uintptr_t)p;
void *q = (void *)q;
// here q is equivalent to p

На многих платформах u хранит адрес объекта, который pуказывают, как и p, и u и p имеют одинаковое представление в памяти.Это не обязательство: реализациям C разрешается использовать другое представление.Но использование того же представления является наиболее очевидным способом выполнения требования стандарта C.

Обратите внимание, что преобразование из uintptr_t в тип указателя дает пригодный для использования указатель, только если было получено значение uintptr_tот указателя, который все еще действителен.Это может быть тонким.Даже на процессорных архитектурах, где представление одинаково (а это почти все), компиляторы могут предполагать, что вы не делаете слишком сумасшедших вещей, и оптимизировать их соответствующим образом.См. ответы на опрос Cerberus для некоторых примеров.

В вашем случае вы не пытались сохранить значение указателя в uintptr_t, вы пытались сохранить его в int.Это не удалось, поскольку на вашей платформе int слишком мало для хранения значения указателя.Очевидно, что на вашей платформе указатели являются 64-битными значениями, а int - 32-битными значениями.Это очень распространенная схема.

  • a - адрес массива.(Это указатель на первый элемент массива, а на вашей платформе указатель просто представлен адресом.).В данном конкретном прогоне это 0x7ffee8d30600.Ничего примечательного там нет.
  • (int) a преобразует адрес a в значение int.Это определяется реализацией.Ваша реализация делает обычное дело: поскольку int слишком мало, оно усекает значение.Усечение указанного выше адреса до 32-разрядного значения без знака дает 0xe8d30600.Чтобы получить значение со знаком, старший бит становится знаковым битом, поэтому a оказывается отрицательным: a равно -388823552.
  • p равно (int *) ((int) a).Это преобразование снова определяется реализацией, и ваша реализация снова делает то же самое, что и большинство других.Он принимает 32-битное значение int со знаком -388823552, расширяет его до желаемой ширины и смещает в диапазон без знака, получая 2 64 - 388823552 = 0xffffffffe8d30600.
  • (int)p применяет тот же процесс усечения, что и (int)a выше, и снова выдает -388823552.Но вы используете спецификатор %x для его распечатки, поэтому это значение преобразуется в unsigned (32-битный тип на вашей платформе), что дает значение 2 32 - 388823552 =0xe8d30600.
0 голосов
/ 02 июня 2019

Я понимаю это. Машина основана на 64-битном адресе. Преобразование адреса в значение int приведет к потере верхнего значения адреса. Таким образом, адрес a отличается от адреса ptr.

Если использовать указатель в C ++, мы можем использовать intptr_t или предпочтительно uintptr_t

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...