访问struct成员就好像它们是单个数组一样?

Dr *_*eco 6 c arrays struct sizeof unions

我有两个结构,其值应该计算一个沉重的平均值,就像这个简化版本:

typedef struct
{
  int v_move, v_read, v_suck, v_flush, v_nop, v_call;
} values;

typedef struct
{
  int qtt_move, qtt_read, qtt_suck, qtd_flush, qtd_nop, qtt_call;
} quantities;
Run Code Online (Sandbox Code Playgroud)

然后我用它们来计算:

average = v_move*qtt_move + v_read*qtt_read + v_suck*qtt_suck + v_flush*qtd_flush + v_nop*qtd_nop + v_call*qtt_call;
Run Code Online (Sandbox Code Playgroud)

现在和他们一起我需要包含另一个变量.现在,例如,我需要包括v_cleanqtt_clean.我无法将结构更改为数组:

typedef struct
{
    int v[6];
} values;
typedef struct
{
    int qtt[6];
} quantities;
Run Code Online (Sandbox Code Playgroud)

这将简化我的工作,但它们是需要变量名称清晰的API的一部分.

所以,我正在寻找一种方法来访问那些结构的成员,也许正在使用sizeof(),所以我可以将它们视为一个数组,但仍然保持API不可更改.保证所有值都是int,但我不能保证一个的大小int.

在我脑海中写下这个问题......能union做到这一点吗?还有另一种聪明的方法可以自动化添加其他成员的任务吗?

谢谢,Beco

AnT*_*AnT 18

你想要做的是不可能以任何优雅的方式做.无法将连续的struct成员可靠地作为数组进行访问.目前接受的答案是黑客,而不是解决方案.

正确的解决方案是切换到一个数组,无论它需要多少工作.如果你使用枚举常量进行数组索引(正如@digEmAll在他现在删除的答案中所建议的那样),那么名称和代码就会像现在一样清晰.

如果您仍然不想或不能切换到数组,那么您尝试做的唯一或多或少可接受的方法是创建"索引数组"或"地图数组"(见下文).C++有一个专门的语言功能,可以帮助人们优雅地实现它 - 指向成员的指针.在C中,您被迫使用offsetof宏来模拟该C++功能

static const size_t values_offsets[] = { 
  offsetof(values, v_move),
  offsetof(values, v_read),
  offsetof(values, v_suck),
  /* and so on */
};

static const size_t quantities_offsets[] = { 
  offsetof(quantities, qtt_move),
  offsetof(quantities, qtt_read),
  offsetof(quantities, qtt_suck),
  /* and so on */
};
Run Code Online (Sandbox Code Playgroud)

如果现在你得到了

values v;
quantities q;
Run Code Online (Sandbox Code Playgroud)

和索引

int i;
Run Code Online (Sandbox Code Playgroud)

你可以生成指向各个字段的指针

int *pvalue = (int *) ((char *) &v + values_offsets[i]);
int *pquantity = (int *) ((char *) &q + quantities_offsets[i]);

*pvalue += *pquantity;
Run Code Online (Sandbox Code Playgroud)

当然,您现在可以i以任何您想要的方式进行迭代.这也远非优雅,但至少它具有一定程度的可靠性和有效性,而不是任何丑陋的黑客.通过将重复的部分包装到适当命名的函数/宏中,可以使整个事物看起来更优雅.


MBy*_*ByD 8

如果保证所有成员都是类型int,则可以使用指向int的指针并将其递增:

int *value = &(values.v_move);
int *quantity = &(quantities.qtt_move);
int i;
average = 0;
// although it should work, a good practice many times IMHO is to add a null as the last member in struct and change the condition to quantity[i] != null.
for (i = 0; i < sizeof(quantities) / sizeof(*quantity); i++)
    average += values[i] * quantity[i];
Run Code Online (Sandbox Code Playgroud)

(因为结构中成员的顺序保证是声明的)


Lin*_*cer 7

在我脑海中写下这个问题......工会可以做这个工作吗?还有另一种聪明的方法可以自动化添加其他成员的任务吗?

是的,一定union可以做到这一点:

union
{
  values v;    /* As defined by OP */
  int array[6];
} u;
Run Code Online (Sandbox Code Playgroud)

您可以u.values在API中使用指针,并u.array在代码中使用.

就个人而言,我认为所有其他答案都打破了最不惊讶的规则.当我看到一个简单的结构定义时,我假设该结构将使用普通访问方法进行访问.使用a union,很明显应用程序将以特殊方式访问它,这促使我特别注意代码.