如何遍历结构成员?

时间:2018-08-21 06:32:57

标签: c

具有这样的结构:

struct _Example {
    int a;
    int b;
    int c;
} Example;

一个函数通过指针获取此struct并输出struct成员的值。我想打印这些值:

Example example;
func(&example);

if(example.a)
    printf("%d", example.a);

if(example.b)
    printf("%d", example.b);

if(example.c)
    printf("%d", example.c);

如何用循环替换那些多个if条件?

3 个答案:

答案 0 :(得分:8)

最好的方法可能是在union上键入修剪。它允许您使用不同的变量表示形式来使用相同的内存区域,例如,通过为每个struct成员指定单独的名称,同时又可以循环遍历它们。

#include <stdio.h>

typedef union {
  struct  // anonymous struct, requires standard C compiler
  {
    int a;
    int b;
    int c;
  };
  int array[3];
} Example;


int main (void)
{
  Example ex = { .a=1, .b=2, .c=3 };

  for(size_t i=0; i<3; i++)
  {
    printf("%d\n", ex.array[i]);
  }
}

如果无法更改结构定义,则第二好的选择是通过字符类型进行某种指针运算。不过,这需要多加注意,这样您才不会最终编写行为定义不当的代码-您需要注意对齐和严格的别名等事情。如果结构因使用不同类型的成员而变得更加复杂,则最好使用字符类型,因为字符类型可以避免别名问题。

假设uint8_t是字符类型,则:

#include <stdio.h>
#include <stdint.h>

typedef union {
  struct
  {
    int a;
    int b;
    int c;
  };
} Example;


int main (void)
{
  Example ex = { .a=1, .b=2, .c=3 };
  uint8_t* begin = (uint8_t*)&ex;
  uint8_t* end   = begin + sizeof ex;


  for(uint8_t* i=begin; i!=end; i+=sizeof(int))
  {
    printf("%d\n", *(int*)i);
  }
}

答案 1 :(得分:1)

简短的答案是,您不能轻易做到这一点。结构中的成员被设计为通过名称进行访问,而不是被设计为被索引的数组中的元素。

可以通过偏移量计算地址,但是无论如何您仍然需要了解结构布局,最重要的是,该布局可以通过编译器选项或pragma进行更改。

将类型信息携带到更复杂的运行时环境中的语言,例如C#和Java,允许您在运行时枚举结构成员,但是C只是创建一个未注释的数据blob,您必须在编译时知道 ,因此您也可以显式枚举成员。当然,您可以使用通常的C技巧;可能有一个序列化解决方案,可以从包装在宏中的某些结构定义中生成用于访问结构元素的代码(啊,是的,第一个Google匹配:https://gist.github.com/Rhomboid/8e48620badbb3d9b4c30)。

之所以可以在运行时为数组的元素建立索引,是因为数组的内部布局是完全已知的(例如,定义为不包含填充)。

当然,您可以定义一个结构,该结构包含足够大的并集数组以容纳最大的元素,该元素带有自己的类型和“成员”名称信息,然后用于解释该信息,并使用在运行时进行适当的类型转换和printf转换字符串。实际上,您将模仿更复杂的运行时环境的某些功能。

答案 2 :(得分:0)

如果您将struct variable视为单独的对象,则不可能

但是如果您将它们视为array,则有可能

例如

struct Example {int member[3];};

int main()
{
     struct Example example;
     int i;
     for (i = 0; i < 3; ++i)
         example.member[i] = i;
}