迭代C中相同类型的struct成员
是否可以使用指针迭代C结构,其中所有成员都是相同类型。 这是一些不编译的示例代码:
#include #include 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结构的成员。
最简单的方法是创建一个联合,一个部分包含每个成员,一个部分包含一个数组。 我不确定平台相关的填充是否会干扰对齐。
使用带arrays的并集的大多数尝试都很容易失败。 只要你只使用int,它们就有很好的工作机会,但对于其他类型,特别是较小的类型,它们可能会经常失败,因为编译器可以(特别是对于较小的类型通常会)在成员之间添加填充。一个struct
,但是不允许使用数组元素这样做。
但是,C确实有一个可以使用的offsetof()
宏。 它会产生struct
项目的偏移量,因此您可以创建一个偏移数组,然后(在投射时要小心)您可以将该偏移量添加到结构的地址以获取该成员的地址。 在转换中的注意是因为偏移量是以字节为单位,因此您需要将struct
的地址强制转换为char *
,然后添加偏移量,然后将结果转换为成员的类型(在您的情况下为int
)。
从语言的角度来看:你做不到。 结构的数据成员在C中不是……呃……“可迭代的”,无论它们是相同类型还是不同类型。
使用数组而不是一堆独立成员。
您还可以使用未命名的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,
int* tmp = &data->mem1 ; // explicitly get the address of the first int member
如你所说,你必须小心对齐和其他内存布局问题。 你应该很好用int
做这个。
但我会质疑这会使您的代码具有可读性。
顺便说一句,
tmp += ( i * sizeof(foo) ) ;
我认为这不符合你的想法,但我不完全确定你想要它做什么。 使用++tmp;
如果你想步入同一个foo
对象的下一个int
成员。
这是另一种方法; 我从来没有理由这样做,但它的优点是不会破坏结构定义。 创建一个指向您感兴趣的成员的指针数组,然后迭代该数组:
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]); }
这样你就不必担心咬你的对齐问题了,你可以任意命令你想要迭代成员的方式(例如,你可以订购它,所以walk是“mem4,mem3,mem2,mem1”)。
您应该能够将foo指针强制转换为int指针。
一个更清洁的解决方案是声明foo如下。
typedef struct { int fooints[ 4 ] ; } foo ;
然后迭代int数组。
for ( int i = 0 ; i < 4 ; i++ ) { printf( "%d\n" , *( foo->fooints + i ) ) ; }
您可以继续创建成员函数来访问和/或操作int数组。