c - 在 C 中使用指针循环遍历结构元素

标签 c pointers structure

我编写这段代码是为了遍历结构的成员。它工作正常。我可以对具有混合类型元素的结构使用类似的方法吗,即一些整数、一些 float 和...?

#include <stdio.h>
#include <stdlib.h>

struct newData
{
    int x;
    int y;
    int z;
}  ;

int main()
{
    struct newData data1;
    data1.x = 10;
    data1.y = 20;
    data1.z = 30;

    struct newData *data2 = &data1;
    long int *addr = data2;
    for (int i=0; i<3; i++)
    {
        printf("%d \n", *(addr+i));
    }
}

最佳答案

在 C 语言中,“工作正常”还不够好。因为你的编译器被允许这样做:

struct newData
{
    int x;
    char padding1[523];
    int y;
    char padding2[364];
    int z;
    char padding3[251];
};

当然,这是一个极端的例子。但是你明白了一般的想法;不能保证您的循环会工作,因为不能保证 struct newData 等同于 int[3]

所以不,在一般情况下这是不可能的,因为在特定情况下并不总是可能的!


现在,您可能会想:“这是什么白痴决定的?!”嗯,我不能告诉你,但我可以告诉你为什么。计算机彼此之间非常不同,如果您希望代码运行得更快,那么编译器必须能够选择如何编译代码。这是一个例子:

处理器 8 有一条指令获取单个字节,并将它们放入寄存器中:

GETBYTE addr, reg

这适用于这个结构:

struct some_bytes {
   char age;
   char data;
   char stuff;
}

struct some_bytes 可以愉快的占用3个字节,代码速度很快。但是处理器 16 呢?它没有GETBYTE,但GETWORD:

GETWORD even_addr, reghl

这只接受一个偶数地址,并读取两个字节;一个进入寄存器的“高”部分,一个进入寄存器的“低”部分。为了使代码更快,编译器必须这样做:

struct some_bytes {
   char age;
   char pad1;
   char data;
   char pad2;
   char stuff;
   char pad3;
}

这意味着代码可以运行得更快,但也意味着您的循环将无法运行。不过没关系,因为它是一种叫做“未定义行为”的东西;允许编译器假定它永远不会发生,如果它确实发生了,则行为是未定义的。

事实上,您已经遇到过这种行为!您的特定编译器正在执行此操作:

struct newData
{
    int x;
    int pad1;
    int y;
    int pad2;
    int z;
    int pad3;
};

因为您的特定编译器将 long int 定义为 int 长度的两倍,所以您可以这样做:

|  x  | pad |  y  | pad |  z  | pad |

| long no.1 | long no.2 | long no.3 |
| int |     | int |     | int |     

正如您从我不稳定的图表中看出的那样,该代码是不稳定的。它可能不会在其他任何地方工作。更糟糕的是,如果您的编译器足够聪明的话,它能够做到这一点:

for (int i=0; i<3; i++)
{
    printf("%d \n", *(addr+i));
}

Hmm... addr is from data2 which is from data1 which is a pointer to a struct newData. The C specification says that only the pointer to the start of the struct will ever be dereferenced, so I can assume that i is always 0 in this loop!

for (int i=0; i<3 && i == 0; i++)
{
    printf("%d \n", *(addr+i));
}

That means it only runs once! Hooray!

printf("%d \n", *(addr + 0));

And all I need to compile is this:

int main()
{
    printf("%d \n", 10);
}

Wow, the programmer will be so pleased that I've managed to speed this code up so much!

你不会高兴的。事实上,您会遇到意想不到的行为,并且无法找出原因。但是,如果您编写的代码没有未定义行为,并且您的编译器做了类似的事情,您感到高兴。所以它留下来。

关于c - 在 C 中使用指针循环遍历结构元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52859148/

相关文章:

c - 递归删除重复字符

编译器不识别 __STATIC_INLINE

c++ - 在 C++ 中使用 new 分配内存和重新解释指针

c++ - 填充指向返回结构的类获取函数的指针数组

c++ - 将堆栈实现为链接结构的解码器

为网络选择声音编解码器 (c/c++)

c++ - 函数返回类型和名称之间存在未知关键字

c - c中的链表遍历

zend-framework - Zend Framework 应用程序的默认模块化目录结构

c++ - 如何在多变量结构的 '<' 实现中不迷路