使用类型定义的数据类型取消通用指针的引用

时间:2018-11-22 04:45:44

标签: c pointers structure void-pointers dereference

我的代码如下所示

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值。请任何人提供帮助并提供解决此问题的想法。

2 个答案:

答案 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