使用指针访问结构成员

时间:2012-12-13 09:25:14

标签: c iterator structure

在C中,我有这样的结构

typedef struct
{
 char *msg1;
 char *msg2;
 .
 .
 char *msgN;
}some_struct;

some_struct struct1;
some_struct *pstruct1 = &struct1;

我想保留一个指针或变量,当递增或递减时,给出该结构的下一个/最后一个成员变量。我不想使用char *数组,因为它已经像这样设计了。

我尝试使用union和structure组合,但我不知道如何编写代码。

思想迭代器可能有所帮助,但这是C. 有什么建议 ?

3 个答案:

答案 0 :(得分:2)

你不能安全地做到这一点。您可以冒险将相邻的字符指针真正相邻(没有填充),就像它们在数组中一样,但是您无法确定这是否非常直接进入未定义的行为雷区。

您可以将其抽象为索引,并执行以下操作:

char * get_pointer(some_struct *p, int index)
{
  if(index == 0)
    return p->msg1;
  if(index == 1)
    return p->msg2;
  /* and so on */
  return NULL;
}

然后你可以使用一个可以自由递增/递减的索引,只需在需要时调用get_pointer()将它映射到一个消息指针。

答案 1 :(得分:2)

您可以使用严格的C来执行此操作,但您需要采取某些预防措施以确保符合标准。我将在下面解释这些,但您需要采取的预防措施是:

(0)通过包含此声明确保没有填充:

extern int CompileTimeAssert[
    sizeof(some_struct) == NumberOfMembers * sizeof(char *) ? 1 : -1];

(1)从结构的地址初始化指针,而不是成员的地址:

char **p = (char **) (char *) &struct1;

(我怀疑上面没有必要,但我必须从C标准中插入更多推理。)

(2)按以下方式递增指针,而不是使用++或添加一个:

p = (char **) ((char *) p + sizeof(char *));

以下是解释。

(0)中的声明充当编译时断言。如果结构中没有填充,则结构的大小等于成员数乘以成员的大小。然后三元运算符求值为1,声明有效,编译器继续。如果有填充,大小不相等,则三元运算符求值为-1,并且声明无效,因为数组不能具有负大小。然后编译器报告错误并终止。

因此,只有在结构没有填充时,才会编译包含此声明的程序。此外,声明不会消耗任何空间(它只声明一个永远不会定义的数组),并且它可以与其他表达式重复(如果条件为真,则计算为数组大小为1),因此不同的断言可能是使用相同的数组名称进行测试。

项目(1)和(2)处理的问题是指针算法通常只能在数组中起作用(最后包括一个名义上的哨兵元素)(根据C 2011 6.5.6 8)。但是,C标准对字符类型进行了特殊保证,在C 2011 6.3.2.3中7.指向结构的指针可以转换为指向字符类型的指针,它将产生指向结构的最低寻址字节的指针。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。

在(1)中,我们从C 2011 6.3.2.3 7中知道,(char *) &struct1是指向struct1的第一个字节的指针。当转换为(char **)时,它必须是指向struct1的第一个成员的指针(特别感谢C 2011 6.5.9 6,它保证了相等的指针指向同一个对象,即使它们有不同的类型。)

最后,(2)解决了这样一个事实,即数组算术不能直接保证对我们的指针起作用。也就是说,p++将增加一个严格不在数组中的指针,因此6.5.6不能保证算术8.所以我们将它转​​换为char *,保证增量按照6.3.2.3 7的规定,我们将它增加四次,然后将其转换回char **。这必须产生一个指向下一个成员的指针,因为没有填充。

有人可能会声称添加char **(例如4)的大小与一个char的四个增量不同,但标准的意图当然是允许一个地址来处理字节以合理的方式对象。但是,如果您想避免这种批评,可以将+ sizeof(char *)更改为+1+1+1+1(对于大小为4的实现)或+1+1+1+1+1+1+1+1(其中它为8)。

答案 2 :(得分:0)

获取第一个成员的地址并将其存储到char **

char **first = &struct1.msg1;
char **last = &struct1.msg1 + sizeof(some_struct) / sizeof(char *) - 1;

char **ptr = first;  /* *ptr is struct.msg1 */
++ptr;               /* now *ptr is struct1.msg2 */

这假设结构只包含char *个成员。