我的代码如下所示
typedef unsigned short uint16;
struct STR
{
const int x;
const uint16 y;
const int z;
void* sptr;
};
struct STR s2[2] =
{
{1, 4, 6, {&s2[0].x, &s2[0].y, &s2[0].z}},
{10,40, 60, {&s2[1].x, &s2[1].y, &s2[1].z}}
};
int main()
{
void* tptr = s2[0].sptr;
printf("%d %d %d", *((int*)tptr), *( (uint16*)tptr+1 ), *((int*)tptr+2));
return 0;
}
这里我使用的是void指针,因为我将从结构中引用不同的数据类型。我期望得到的输出是
预期输出:1 4 6
但是如果我使用
printf("%d %d %d", *((int*)tptr), *( (uint16*)tptr+1 ), *((int*)tptr+2));
我得到的输出为1 06。在这里,我使用类型定义的数据类型uint16进行延迟。
如果我使用
printf("%d %d %d", *((int*)tptr), *( (int*)tptr+1 ), *((int*)tptr+2));
我得到的正确输出为1 46。为什么uint16类型不能取消引用指针并获得0值。请任何人提供帮助并提供解决此问题的想法。
答案 0 :(得分:0)
我在这里看到一些问题。首先,您不能声明这样的结构。 void *
变量是一个指针。您试图在其位置定义整个结构,并使用错误的语法来做到这一点。我很惊讶编译器没有拒绝代码。
您显然需要定义一个结构,该结构也接受3个整数指针作为值。如果您真的想一次声明所有内容,并且让第四个元素成为指针,则可以使用如下的复合文字:
#pragma GCC diagnostic ignored "-Wmissing-braces"
struct other_struct {
const int *x;
const uint16 *y;
const int *z;
};
struct STR s2[2] = {
{1, 4, 6, (struct other_struct[1]){&s2[0].x, &s2[0].y, &s2[0].z}},
{10,40, 60, (struct other_struct[1]){&s2[1].x, &s2[1].y, &s2[1].z}}
};
请注意,编译器可能会在文件范围内拒绝复合文字(我认为MSCV会这样做)。
您似乎也是这里填充的受害者。编译器将始终尝试将结构中的数据与计算机字长的倍数对齐(64位为8字节),除非您明确要求不要这样做。此外,事物通常排列成至少4个字节的边界(整数的大小)。由于您所做的是完全未定义的行为,因此编译器只是尝试通过为每个元素赋予整数大小来扩展结构。当您尝试查看结构中的下一个int16时,您会向前看2个字节,但是下一个值实际上是在前4个字节,因此得到的值为0。这也解释了为什么当您强制转换为{{1 }}。
编辑:实际上我在上面犯了一个错误。抱歉。您的代码未按预期运行,不一定是因为填充,而是因为您编写了指针算术的方式。试图以这种方式在原始数组中查找元素确实是不可能的,而且无论如何肯定是不确定的行为。
答案 1 :(得分:0)
感谢您的评论。为了解决这个不确定的行为问题,在结构的存储矩阵中。我将结构中的void指针替换为指针数组,并在双指针的帮助下对其进行了访问,现在可以正常使用了。但是它会消耗更多的内存。这样的新代码
typedef unsigned short uint16;
struct STR
{
const int x;
const uint16 y;
const int z;
void* sptr[3];
};
struct STR s2[2] =
{
{1, 4, 6, {&s2[0].x, &s2[0].y, &s2[0].z}},
{10,40, 60, {&s2[1].x, &s2[1].y, &s2[1].z}}
};
int main()
{
void** tptr = s2[0].sptr;
printf("%d %d %d", *((int*)*tptr), *( (uint16*)*(tptr+1)), *((int*)*(tptr+2)));
return 0;
}
//Output: 1 4 6