Доступ к значению с адреса в C - PullRequest
0 голосов
/ 09 октября 2018

Вот мой код

struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };

struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
unsigned int *p = (unsigned int *)malloc(sizeof(unsigned int));
p[0] = k;    
int *vp;
vp = ((uint8_t *)p[0] + 4);
printf("%d\n", *vp);

Это приводит к ошибке сегментации.Однако если мы заменим последнюю строку на printf("%u\n", vp), то получим адрес, т.е. &(k->saddr.val[0]).Однако я не могу напечатать значение, присутствующее по адресу, используя p[0], но могу напечатать его, используя k->saddr.val[0].

Мне нужно каким-то образом использовать указатель p для доступа к значению на val[0], я не могу использовать указатель k.Мне нужна помощь, возможно ли это или нет, пожалуйста, дайте мне знать.

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Здесь много "грязного" беспорядка с адресами, сделанными здесь.Некоторые из этих вещей не рекомендуются или даже запрещены со стандартной точки зрения C.

Однако такие подстройки указателя / адреса обычно используются в низкоуровневом программировании (встроенные, встроенные программы и т. Д.), Когда некоторые детали реализации компилятораизвестны пользователю.Конечно, такой код не является переносимым.

В любом случае проблема здесь (после получения более подробной информации в разделе комментариев) заключается в том, что машина, на которой выполняется этот код, имеет 64-битную версию.Таким образом, указатели имеют ширину 64 бита, в то время как int или unsigned int имеют ширину 32 бита.

Таким образом, при сохранении адреса k в p[0]

 p[0] = k;

, в то время как p[0] имеет тип unsigned int, а k имеет указатель типа на struct kai, старшие 32 бита значения k обрезаны.

Чтобы решить эту проблему, лучше всегоиспользуйте uintptr_t, так как этот тип всегда будет иметь нужную ширину для хранения полного значения адреса.

uintptr_t *p = malloc(sizeof(uintptr_t));

Примечание : uintptr_t необязательно, но обычно.Это достаточно для void*, но, возможно, не указатель на функцию.Для совместимого кода правильное использование uintptr_t включает указатель объекта -> void * -> uintptr_t -> void * -> указатель объекта .

0 голосов
/ 09 октября 2018

Код не имеет смысла:

  • p[0] = k; преобразует значение указателя k в int, поскольку p является указателем на int.Это определяется реализацией и теряет информацию, если указатели больше, чем тип int.
  • vp = ((uint8_t *)p[0] + 4);, преобразует int, на который указывает p, в указатель на unsigned char и заставляет vp указывать нарасположение 4 байта за указателем.Если указатели больше int, это ведет к неопределенному поведению.Можно просто распечатать значение этого фиктивного указателя, но разыменование имеет неопределенное поведение.
  • printf("%u\n", vp) использует неверный формат для указателя vp, опять же, это неопределенное поведение, хотя вряд лиcrash.

Скорее всего, проблема связана с размером указателей и целых чисел: если вы скомпилируете этот код как 64-битные, указатели будут больше, чем int, поэтому преобразование одного в другой приводит к потере информации.

Вот исправленная версия:

struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };

struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
int **p = malloc(sizeof *p);
p[0] = k;    
int *vp = (int *)((uint8_t *)p[0] + sizeof(int));
printf("%d\n", *vp);  // should print 6
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...