使用C中的指针循环结构元素

Ima*_*n H 4 c pointers structure

我编写了这段代码来迭代结构的成员.它工作正常.我可以对具有混合类型元素的结构使用类似的方法,即一些整数,一些浮点数和......?

#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));
    }
}
Run Code Online (Sandbox Code Playgroud)

wiz*_*zz4 7

在C中,"它工作正常"还不够好.因为允许您的编译器执行此操作:

struct newData
{
    int x;
    char padding1[523];
    int y;
    char padding2[364];
    int z;
    char padding3[251];
};
Run Code Online (Sandbox Code Playgroud)

当然,这是一个极端的例子.但是你得到了一般的想法; 它不能保证你的循环可以工作,因为它不能保证struct newData相当于int[3].

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


现在,你可能会想:"白痴决定了什么?!" 好吧,我不能告诉你,但我可以告诉你为什么.计算机彼此非常不同,如果您希望代码快速运行,那么编译器必须能够选择如何编译代码.这是一个例子:

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

GETBYTE addr, reg
Run Code Online (Sandbox Code Playgroud)

这适用于这个结构:

struct some_bytes {
   char age;
   char data;
   char stuff;
}
Run Code Online (Sandbox Code Playgroud)

struct some_bytes可以愉快地占用3个字节,代码很快.但是处理器16呢?它没有GETBYTE,但确实GETWORD:

GETWORD even_addr, reghl
Run Code Online (Sandbox Code Playgroud)

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

struct some_bytes {
   char age;
   char pad1;
   char data;
   char pad2;
   char stuff;
   char pad3;
}
Run Code Online (Sandbox Code Playgroud)

这意味着代码可以更快地运行,但这也意味着你的循环不起作用.那没关系,因为它叫做"未定义的行为"; 允许编译器假设它永远不会发生,如果它确实发生,则行为是未定义的.

事实上,你已经遇到过这种行为!你的特定编译器是这样做的:

struct newData
{
    int x;
    int pad1;
    int y;
    int pad2;
    int z;
    int pad3;
};
Run Code Online (Sandbox Code Playgroud)

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

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

| long no.1 | long no.2 | long no.3 |
| int |     | int |     | int |     
Run Code Online (Sandbox Code Playgroud)

正如你可以从我不稳定的图表中看到的那样,这段代码是不稳定的.它可能无法在其他任何地方工作.更糟糕的是,你的编译器,如果它很聪明,就能做到这一点:

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

嗯... addrdata2这是data1这是一个指针struct newData.C规范说只有指向结构开头的指针才会被取消引用,所以我可以假设它i总是0在这个循环中!

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

这意味着它只运行一次!万岁!

printf("%d \n", *(addr + 0));
Run Code Online (Sandbox Code Playgroud)

我需要编译的是:

int main()
{
    printf("%d \n", 10);
}
Run Code Online (Sandbox Code Playgroud)

哇,程序员会非常高兴我已经设法加快了这个代码的速度!

你不会高兴的.事实上,你会得到意想不到的行为,并且无法解决原因.但是如果您编写的代码没有未定义的行为,并且您的编译器已经做了类似的事情,那么您很高兴.所以它保持不变.