是否可以使用指针迭代C结构,其中所有成员都是相同类型。以下是一些无法编译的示例代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int mem1 ;
int mem2 ;
int mem3 ;
int mem4 ;
} foo ;
void my_func( foo* data )
{
int i ;
int* tmp = data ; // This line is the problem
for( i = 0; i < 4; ++i )
{
++tmp ;
printf( "%d\n", *tmp ) ;
}
}
int main()
{
foo my_foo ;
//
my_foo.mem1 = 0 ;
my_foo.mem2 = 1 ;
my_foo.mem3 = 2 ;
my_foo.mem4 = 3 ;
//
my_func( &my_foo ) ;
return 0 ;
}
foo的成员应该在内存中一个接一个地对齐,假设你的编译器/内核没有尝试为缓冲区溢出提供堆栈保护。
所以我的问题是:
我如何迭代相同类型的C结构的成员。
答案 0 :(得分:14)
使用与数组的并集的大多数尝试都很容易失败。只要你只使用int,它们就有很好的工作机会,但对于其他类型,特别是较小的类型,它们可能会经常失败,因为编译器可以(特别是对于较小的类型通常会)在成员之间添加填充。 struct
,但不允许使用数组元素。
C确实有一个offsetof()
宏可以使用。它会产生struct
中项目的偏移量,因此您可以创建一个偏移数组,然后(在投射时要小心)您可以将该偏移量添加到结构的地址以获取地址会员。关注是因为偏移量是以字节为单位的,所以你需要将struct
的地址转换为char *
,然后添加偏移量,然后将结果转换为成员的类型({在你的情况下{1}}。
答案 1 :(得分:5)
从语言的角度来看:你做不到。结构的数据成员在C中不是......呃......“可迭代的”,无论它们是相同类型还是不同类型。
使用数组而不是一堆独立成员。
答案 2 :(得分:3)
最简单的方法是创建一个联合,一个部分包含每个成员,一个部分包含一个数组。我不确定平台相关的填充是否会干扰对齐。
答案 3 :(得分:2)
您还可以使用未命名的union / struct:
struct foo {
union {
struct {
int mem1;
int mem2;
int mem3;
int mem4;
};
int elements[4];
};
};
foo thefoo;
for (int i = 0; i < 4; ++i) {
thefoo.elements[i] = i;
}
这可能对某些编译器不起作用,在这种情况下,您必须在foo
内明确命名union和struct,
答案 4 :(得分:1)
int* tmp = &data->mem1 ; // explicitly get the address of the first int member
正如您所说,您必须小心对齐和其他内存布局问题。你可以使用int
来做到这一点。
但我会质疑这会使您的代码具有可读性。
顺便提及,
tmp += ( i * sizeof(foo) ) ;
我认为这不符合您的想法,但我不完全确定您希望它做什么。如果您要转到同一++tmp;
个对象的下一个int
成员,请使用foo
。
答案 5 :(得分:1)
这是另一种方法;我从来没有理由这样做,但它的优点是不会破坏结构定义。创建一个指向您感兴趣的成员的指针数组,然后迭代该数组:
typedef struct { int mem1; int mem2; int mem3, int mem4; } foo;
...
foo theStruct;
int *structMembers[4] = { &theStruct.mem1, &theStruct.mem2,
&theStruct.mem3, &theStruct.mem4};
...
for (i = 0; i < 4; i++)
{
printf("%d\n", *structMembers[i]);
}
这样你就不必担心咬你的对齐问题了,你可以任意命令你想要迭代成员的方式(例如,你可以订购它以便步行是“mem4,mem3,mem2,mem1 “)。
答案 6 :(得分:0)
您应该能够将foo指针强制转换为int指针。
更清洁的解决方案是按如下方式声明foo。
typedef struct
{
int fooints[ 4 ] ;
} foo ;
然后迭代int数组。
for ( int i = 0 ; i < 4 ; i++ )
{
printf( "%d\n" , *( foo->fooints + i ) ) ;
}
您可以继续创建成员函数来访问和/或操作int数组。
答案 7 :(得分:0)
我发现迭代具有相同数据类型成员的结构的最佳方法;
用想要的名字创建一个枚举。添加迭代限制的最后一个元素。创建一个包含大小为 TOTAL_STRUCT_MEMBERS 的数组的结构。然后用 for 迭代。
enum StructMembers{
data1,
data2,
data3,
TOTAL_STRUCT_MEMBERS
};
struct DataStruct{
int datas[TOTAL_STRUCT_MEMBERS];
};
// iterating
for(int i = 0; i < TOTAL_STRUCT_MEMBERS; i++)
{
DataStruct.datas[i] = 0;
}
// Direct access
DataStruct.datas[data2] = 25;