在c中引用带有方括号和索引的结构字段而不是.和 - >?

lsi*_*ert 7 c struct

假设我有一个结构如:

typedef struct
{
    char * string1;
    char * string2;
} TWO_WORDS;
Run Code Online (Sandbox Code Playgroud)

这样所有的字段都是相同的类型,而我的主要字段

TWO_WORDS tw;
Run Code Online (Sandbox Code Playgroud)

我可以用tw [0]引用string1,用两个[1]引用string2吗?如果是这样:

  • 这是c标准的一部分吗?
  • 我必须先将结构转换为数组吗?
  • 那些在内存中大小不同的字段呢?
  • 那些不同类型但大小相同的字段呢?
  • 你能在结构中做指针运算吗?
  • -

twa*_*erg 6

正如@ouah指出的那样,不,你不能这么做.但是,您可以:

typedef union
{ char *a[2];
  struct
  { char *string1;
    char *string2;
  } s;
} TWO_WORDS;

TWO_WORDS t;

t.a[0] = ...;
t.a[1] = ...;
t.s.string1 = ...;
t.s.string2 = ...;
Run Code Online (Sandbox Code Playgroud)


abe*_*nky 5

我很接近这个构造:

((char**)&tw)[0];
Run Code Online (Sandbox Code Playgroud)

举个例子:

int main()
{
    typedef struct
    {
        char * string1;
        char * string2;
    } TWO_WORDS;

    TWO_WORDS tw = {"Hello", "World"};

    printf("String1: %s\n", ((char**)&tw)[0]);
    printf("String2: %s\n", ((char**)&tw)[1]);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

由于编译器可能会在字段之间添加填充,因此不能保证能正常工作。(许多编译器都有一个#pragma可避免填充结构的)

要回答您的每个问题:

  • 这是C标准的一部分吗?没有

  • 我必须首先将结构转换为数组吗?

  • 内存中大小不同的字段呢?
    这可以通过更多的“邪恶”转换和指针运算来完成。

  • 那些类型不同但大小相同的字段呢?
    这可以通过更多的“邪恶”转换和指针运算来完成

  • 您可以在结构内执行指针算术吗?
    是的 (不能保证总是能按您期望的那样工作,但是结构只是一块内存,您可以使用指针和指针进行访问)


AnT*_*AnT 5

不,您不能对结构数据成员使用索引访问,除非您采取特定步骤来模拟它。

在 C++ 中,可以使用称为“指向数据成员的指针”的特定于 C++ 的指针类型来模拟此功能。C 语言没有这样的类型,但反过来可以通过使用标准offsetof宏和指针算法来模拟它。

在您的示例中,它可能如下所示。首先,我们准备一个特殊的偏移数组

const size_t TW_OFFSETS[] = 
  { offsetof(TWO_WORDS, string1), offsetof(TWO_WORDS, string2) };
Run Code Online (Sandbox Code Playgroud)

此偏移数组稍后用于组织对结构成员的索引访问

*(char **)((char *) &tw + TW_OFFSETS[i]); 
/* Provides lvalue access to either `tw.string1` or `tw.string2` depending on 
   the value of `i` */
Run Code Online (Sandbox Code Playgroud)

它看起来并不漂亮(虽然可以通过使用宏使它看起来更好),但这就是它在 C 中的方式。

例如,我们可以定义

 #define TW_MEMBER(T, t, i) *(T *)((char *) &(t) + TW_OFFSETS[i])
Run Code Online (Sandbox Code Playgroud)

并在代码中使用它作为

 TW_MEMBER(char *, tw, 0) = "Hello";
 TW_MEMBER(char *, tw, 1) = "World";

 for (int i = 0; i < 2; ++i)
   printf("%s\n", TW_MEMBER(char *, tw, i));
Run Code Online (Sandbox Code Playgroud)

请注意,这种方法没有基于将结构重新解释为char*[2]数组的解决方案中存在的严重问题(无论它是通过联合还是通过强制转换完成)​​。后者是一种黑客行为,从正式的角度来看是非法的,并且通常无效。该offsetof基于解决方案是完全有效的,合法的。