在不引用内部结构的情况下访问另一个结构中的结构字段

时间:2018-12-17 02:33:08

标签: c struct

假设我有一个结构定义如下:

struct entity {
    int x;
    int y;
};

以及将其用作成员的结构:

struct player {
    struct entity position;
    char* name;
};

如果我编写以下代码,则会出现错误:

struct player p;
p.x = 0;         //error: 'struct player' has no member named 'x'

到目前为止,我一直在写一个函数,该函数接受播放器结构并通过执行return player.position.x返回值。

是否有编译器标志或其他方法可让我“展平”结构(我不确定那是否是正确的短语)结构,并允许我像上面所示的那样访问x变量?我意识到,如果在播放器和实体中都存在一个名为x的整数,这可能是模棱两可的。

请注意,我将在多个结构中使用 entity 结构,因此我不能在 player 中使用匿名结构。

3 个答案:

答案 0 :(得分:2)

简而言之,答案是“否”。如果您看过诸如What are anonymous structs and unions useful for in C11之类的问题却发现它们不是解决方案,则尤其如此。

有关常规的结构和联合类型的更多信息,您可以查看C11 §6.7.2.1 Structure and union specifiers(而有关匿名成员的更多信息,请参见¶13,例如,¶19)。我同意他们不是你所追求的;它们包含一个新定义的类型,该类型没有标签,也没有“声明列表”。

答案 1 :(得分:0)

您可以将其定义为MACRO:

#define ENTITY_MEMBERS int x; int y
struct entity{
    ENTITY_MEMBERS;
}

struct player {
    ENTITY_MEMBERS;
    char* name;
};

实际上,这就是您在C中模仿C ++单一继承的方式。

答案 2 :(得分:0)

使用宏,我们可以创建一个类型生成器:

#define struct_entity(...) \
struct __VA_ARGS__ {       \
  int a;                   \
  int b;                   \
}

然后我们可以随意将这种类型实例化为带标签的结构或匿名结构:

struct_entity(entity);

struct player {
  struct_entity();
  const char *name;
};

int main() {
    struct player player;
    player.a = 1;
    player.b = 2;
    player.name = "bar";
}

此代码的意图与您想要的更接近,并且没有approach of declaring just the structure members in the macro的UB问题。具体来说,struct player内部有一个结构成员,而不是单个成员。这很重要,因为编译器可能会执行填充的减少和成员的重新排序-尤其是在嵌入式目标上。例如。下面的composite_1composite_2不一定具有相同的布局!:

#include <assert.h>
#include <stddef.h>

typedef struct sub_1 {
  int a;
  void *b;
  char c;
} sub_1;

typedef struct sub_2 {
  void *d;
  char e;
} sub_2;

typedef struct composite_1 {
  int a;
  void *b;
  char c;
  void *d;
  char e;
} composite_1;

typedef struct composite_2 {
  struct sub_1 one;
  struct sub_2 two;
} composite_2;

// Some of the asserts below may fail on some architectures.
// The compile-time asserts are necessary to ensure that the two layouts are
// compatible.
static_assert(sizeof(composite_1) == sizeof(composite_2), "UB");
static_assert(offsetof(composite_1, a) == offsetof(composite_2, one.a), "UB");
static_assert(offsetof(composite_1, b) == offsetof(composite_2, one.b), "UB");
static_assert(offsetof(composite_1, c) == offsetof(composite_2, one.c), "UB");
static_assert(offsetof(composite_1, d) == offsetof(composite_2, two.d), "UB");
static_assert(offsetof(composite_1, e) == offsetof(composite_2, two.e), "UB");