代码之家  ›  专栏  ›  技术社区  ›  Misha M

在C中迭代相同类型的结构成员

  •  4
  • Misha M  · 技术社区  · 16 年前

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

    7 回复  |  直到 16 年前
        1
  •  3
  •   Mark Ransom    16 年前

    最简单的方法是创建一个联合,其中一个部分单独包含每个成员,另一个部分包含一个数组。我不确定平台相关的填充是否会干扰对齐。

        2
  •  14
  •   Jerry Coffin    16 年前

    大多数尝试将联合与数组一起使用都容易失败。只要您只使用int,它们就有相当大的工作机会,但是对于其他类型(尤其是较小的类型),它们可能会非常频繁地失败,因为编译器可以(尤其是使用较小的类型)在 struct ,但不允许对数组的元素执行此操作)。

    但是,C有一个 offsetof() 可以使用的宏。它产生一个项目在 结构 ,这样您就可以创建一个偏移数组,然后(在强制转换时要小心一点)将该偏移添加到结构的地址中,以获取成员的地址。强制转换时要注意的是,偏移量以字节为单位,因此需要强制转换 结构 到 char * ,然后添加偏移量,然后将结果强制转换为成员的类型( int 在你的情况下)。

        3
  •  5
  •   AnT stands with Russia    16 年前

    从语言的角度来看:不能。结构的数据成员不是…呃…在C语言中“可迭代”,不管它们是属于同一类型还是属于不同类型。

    使用数组而不是一组独立成员。

        4
  •  2
  •   Andreas Brinck    16 年前

    还可以使用未命名的联合/结构:

    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 ,

        5
  •  1
  •   dave4420    16 年前
        int* tmp = &data->mem1 ;  // explicitly get the address of the first int member
    

    正如您所说,您必须小心对齐和其他内存布局问题。你做这个应该很好 int 尽管如此。

    但我想问一下,这将使您的代码具有多大的可读性。

    偶然地,

        tmp += ( i * sizeof(foo) ) ;
    

    我不认为这会像你想象的那样,但我不完全确定你想要它做什么。使用 ++tmp; 如果你想跳到下一个 int 同一成员 foo 对象。

        6
  •  1
  •   John Bode    16 年前

    这是另一种方法;我从未有过这样做的理由,但它的优点是不破坏结构定义。创建指向感兴趣成员的指针数组,然后在该数组上迭代:

    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”)。

        7
  •  0
  •   William Bell    16 年前

    您应该能够将foo指针转换为int指针。

    一个更清洁的解决方案是如下声明foo。

    typedef struct
    {
        int fooints[ 4 ] ;
    } foo ;
    

    然后迭代int数组。

    for ( int i = 0 ; i < 4 ; i++ )
    {
        printf( "%d\n" , *( foo->fooints + i ) ) ;
    }
    

    您可以继续创建成员函数来访问和/或操作int数组。

    推荐文章