迭代C中相同类型的struct成员

时间:2009-12-08 20:56:47

标签: c struct iteration

是否可以使用指针迭代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结构的成员。

8 个答案:

答案 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;