Преобразование int в int * затем обратно в int - PullRequest
5 голосов
/ 12 февраля 2011

Я упускаю что-то очевидное здесь, но учтите следующее,

int k = 10;
int *p = &k;
int i = (int)p;

выше производит,

warning: cast from pointer to integer of different size

и далее,

int k = 10;
int *p = &k;
int i = p;

причины,

warning: initialization makes integer from pointer without a cast

немного погуглил меня,

Преобразование указателя в целое число

, которое рекомендует использовать uintptr_t,

int k = 10;
int *p = &k;
int i = (uintptr_t)p;

выше работает без ошибок, без предупреждений.Поэтому мой вопрос: k - это int, а p - указатель на int, указывающий на k, почему я получаю разыменование по ошибке p?

Ответы [ 7 ]

9 голосов
/ 12 февраля 2011
int k = 10;
int *p = &k;
int i = *p;

Обратите внимание на * перед p в последней строке. Разыменуйте указатель, чтобы получить int, на который он указывает.

РЕДАКТИРОВАТЬ: я не очень знаком с uintptr_t, но я запустил код int i = (uintptr_t) p; Результатом, который сохраняется в i, является адрес памяти k, а не 10. Приведение говорит компилятору, что вы действительно хотите превратить адрес в целое число (поэтому нет предупреждения; потому что вы настаиваете на том, что компилятор знает, что вы делаете), но не разыменовывает указатель.

3 голосов
/ 12 февраля 2011

Вы получаете ошибку, потому что вы на самом деле не разыменовываете p, вы просто преобразовали ее (принудительно изменили тип) с int*.Для разыменования вам нужно использовать оператор *, например:

int i = *p;
2 голосов
/ 12 февраля 2011

Вы не разыменовываете указатель, поэтому вы присваиваете адрес указателя на int.

int i = *p;

Это то, что вы, скорее всего, хотели.

1 голос
/ 12 февраля 2011

Вы устанавливаете i равным адресу k (это то, что p содержит).И значение адреса является беззнаковым типом.Таким образом, при приведении из указателя он жалуется, потому что вы берете приведение и значение без знака для подписанного.

Кроме того, указатели являются типоразмерами разных типов в зависимости от платформы, поэтому 32-разрядные указатели меньше 64. Поэтому, если указатель является 8-байтовым без знака, вы приводите его к 4-байтовому знаку.

1 голос
/ 12 февраля 2011

Вы играете с int на приведение указателя, и это не гарантирует, что эти двое даже больше используют один и тот же объем памяти.На самом деле у него не было гарантии использования того же размера, когда люди делали это, но для большинства платформ это все равно работало.

Поскольку вы явно приводите в последнем примере, компилятор предполагаетЭто не ошибка (или почему вы бы это напечатали?).В этом причина различий в выводе компилятора.

Обратите внимание, что если вы не хотите сохранять адрес памяти k в i, то правильный способ получить значение K в i будет

int i = *p;
0 голосов
/ 12 февраля 2011

uintptr_t не подразумевается как тип для выполнения промежуточного приведения к int, но используется как таковой.Если он определен в системе (а у вас, кажется, он есть), это целочисленный тип без знака, где вы не теряете информацию, когда загружаете ее значением указателя.Поэтому, если необходимо, используйте uintprt_t полностью вместо int.Но это должно быть в редких случаях, и в большинстве случаев, я бы поспорил, это просто признак плохого дизайна.

В любом случае int - плохая идея с самого начала.Во всяком случае, значение указателя - это просто позиция в пространстве виртуальной памяти, и рассматривать его как значение со знаком вообще не имеет смысла для меня.

0 голосов
/ 12 февраля 2011

вот так это должно выглядеть

int k = 10;
int *p = &k;
int i = *p;

вот как я думаю об этом

k = 10

p = некоторый адрес

& k = некоторый адрес

* р = 10

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