从C中的地址访问值

问题描述 投票:1回答:2

这是我的代码

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。我在这里需要帮助,无论是否可能,请告诉我。

c pointers malloc
2个回答
0
投票

在这里完成的地址有很多“脏”的混乱。从标准C的角度来看,不推荐甚至禁止使用其中一些内容。

然而,当用户已知某些编译器实现细节时,这种指针/地址调整通常用于低级编程(嵌入式,固件等)。当然这样的代码不可移植。

无论如何,这里的问题(在评论部分获得更多细节之后)是运行此代码的机器是64位。因此,指针是64位宽度,而intunsigned int是32位宽度。

所以当在k存储p[0]的地址时

 p[0] = k;

虽然p[0]unsigned int类型而k是指向struct kai的类型指针,但k值的高32位被截断。

要解决此问题,最好的方法是使用uintptr_t,因为此类型总是具有适当的宽度来保存完整的地址值。

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

注意:uintptr_t是可选的,但很常见。对于void*来说就足够了,但也许不是函数指针。对于兼容代码,正确使用uintptr_t包括对象指针 - > void * - > uintptr_t - > void * - >对象指针。


3
投票

代码毫无意义:

  • 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,再次这是未定义的行为,虽然它不太可能崩溃。

问题很可能与指针和整数的大小有关:如果将此代码编译为64位,则指针大于整数,因此将一个指针转换为另一个指令会丢失信息。

这是一个更正版本:

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
© www.soinside.com 2019 - 2024. All rights reserved.