pointers - 在C 中,使用指针遍历结构元素

  显示原文与译文双语对照的内容
106 1

我编写了这段代码来迭代结构成员。我们可以以使用混合类型元素的类似方法,换句话说,有些整数,一些浮点和。"。"。

#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));
 }
}
时间:原作者:0个回答

68 5

简短的答案是"没有"。

更长的答案:你的"工时"的示例不是真正合法的,。如果根据任何原因,你真的希望能够循环多种类型,你可以以使用结构和联合来获得创造性。例如具有一个结构的结构,该结构通知它的他成员所持有的数据类型。另一个成员将是所有可能数据类型的联合。像这样:

#include <stdio.h>
#include <stdlib.h>
enum TYPE {INT, DOUBLE};
union some_union {
 int x;
 double y;
};
struct multi_type {
 enum TYPE type;
 union some_union u;
};
struct some_struct {
 struct multi_type array[2];
};
int main(void) {
 struct some_struct derp;
 derp.array[0].type = INT;
 derp.array[0].u.x = 5;
 derp.array[1].type = DOUBLE;
 derp.array[1].u.y = 5.5;
 for(int i = 0; i <2; ++i) {
 switch (derp.array[i].type) {
 case INT:
 printf("Element %d is type 'int' with value %dn", i, derp.array[i].u.x);
 break;
 case DOUBLE:
 printf("Element %d is type 'double' with value %lfn", i, derp.array[i].u.y);
 break;
 }
 }
 return EXIT_SUCCESS;
}

当联合中的元素类型大大差异时,它会造成空间浪费。例如,如果不仅仅是使用 intdouble,那么就有一些大的复杂结构,即使是简单的int 元素。

或者者,如果你没有直接处于结构中的数据,但只存在指向数据的指针,则可以以使用类似的技术。

#include <stdio.h>
#include <stdlib.h>
enum TYPE {INT, DOUBLE};
struct multi_type {
 enum TYPE type;
 void *data;
};
struct some_struct {
 struct multi_type array[2];
};
int main(void) {
 struct some_struct derp;
 int x;
 double y;
 derp.array[0].type = INT;
 derp.array[0].data = &x;
 *(int *)(derp.array[0].data) = 5;
 derp.array[1].type = DOUBLE;
 derp.array[1].data = &y;
 *(double *)derp.array[1].data = 5.5;
 for(int i = 0; i <2; ++i) {
 switch (derp.array[i].type) {
 case INT:
 printf("Element %d is type 'int' with value %dn", i, *(int *)derp.array[i].data);
 break;
 case DOUBLE:
 printf("Element %d is type 'double' with value %lfn", i, *(double *)derp.array[i].data);
 break;
 }
 }
 return EXIT_SUCCESS;
}

不过在做任何事情之前,我建议再次考虑设计,并考虑是否需要重新设计,或者在不同类型的元素之间循环,例如在每种类型的元素之间循环。

原作者:
69 2

在C 中,"效果不错"不够好。因为你的编译器可以执行以下操作:

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

当然,这是一个极端的例子。但是你得到了一般的思想,并不保证你的循环将会工作,因为它不保证 struct newData 等于 int[3]

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

现在,你可能想:"idiots decided decided decided 我不能告诉你,但我不能告诉你为什么。计算机相互不同,如果希望代码快速运行,编译器必须能够选择编译代码。下面是一个示例:

处理器 8有一个指令来获取单个字节,并将它们放入 register:

GETBYTE addr, reg

这里结构适用于以下结构:

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

struct some_bytes 可以很好地占用 3字节,而且代码是快速的。但是处理器 16?它没有 GETBYTE,但它没有:

GETWORD even_addr, reghl

它只接受偶数个地址,读取两个字节;一个进入 register的"高"部分,一个进入 register的"低"部分。为了使代码快速,编译器必须执行以下操作:

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));
}

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

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

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

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

而我需要编译的是:

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

哇,程序员会非常高兴我已经经非常高兴地加速了这个代码 !

你将不会很高兴,事实上,你将会得到意外的行为,并且不能解决原因。但是,如果你编写了无定义行为的代码,并且编译器执行了类似的操作,那么你将会感到很高兴。所以它保持。

原作者:
...