0

在C中,我有这样的结构

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

some_struct struct1;
some_struct *pstruct1 = &struct1;

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

我尝试使用联合和结构组合,但我不知道如何为此编写代码。

认为迭代器可能会有所帮助,但这是 C。有什么建议吗?

4

3 回答 3

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 不能保证算术。所以我们将其转换为 a char *,对于它的增量保证在 6.3.2.3 7 时有效,我们增加它四次,我们将其转换回char **. 这必须产生一个指向下一个成员的指针,因为没有填充。

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

于 2012-12-13T12:52:28.203 回答
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()在需要时调用以将其映射到消息指针。

于 2012-12-13T09:33:01.190 回答
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 *成员。

于 2012-12-13T09:32:21.473 回答