0

Suppose I have a struct that is defined as the following:

struct entity {
    int x;
    int y;
};

And a struct that uses it as a member:

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

If I write the following code then I get an error:

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

What I have been doing so far is writing a function that takes a player struct and returns the value by doing return player.position.x.

Is there a compiler flag, or other method, that allows me to "flatten" (I'm not sure if that's the correct phrase) the struct and allows me to access the x variable like I have shown above? I realize that this might be ambiguous if there is also an integer named x inside player as well as in entity.

Please note I will be using the entity struct in multiple structs and so I cannot use a anonymous struct inside player.

TheCrifix
  • 79
  • 1
  • 3
  • 11

3 Answers3

2

Put succinctly, the answer is "No". This is especially true if you've looked at questions such as What are anonymous structs and unions useful for in C11 and found them not to be the solution.

You can look at C11 §6.7.2.1 Structure and union specifiers for more information about structure and union types in general (and ¶13 specifically for more information about anonymous members, and ¶19 for an example). I agree that they are not what you're after; they involve a newly defined type with no tag and no 'declarator list'.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

You can define then as MACROs:

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

struct player {
    ENTITY_MEMBERS;
    char* name;
};

Actually this is how you mimic C++ single inheritance in C.

W.H
  • 1,838
  • 10
  • 24
0

Using a macro, we can make a type generator:

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

Then we can instantiate that type as either a tagged or anonymous structure, at will:

struct_entity(entity);

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

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

This code is closer in intent to what you want, and doesn't have the UB problem of the approach of declaring just the structure members in the macro. Specifically, there is a structure member inside of struct player, instead of individual members. This is important, because padding reduction and reordering of members may be performed by the compiler - especially on embedded targets. E.g. composite_1 and composite_2 below do not necessarily have the same layout!:

#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");
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Standard C does not allow the compiler to reorder the elements of a structure. Obviously, there might be compilers on specific platforms that do such reordering, presumably using some platform-specific directive (compilation option, pragma or similar) to enable it. – Jonathan Leffler Jan 02 '19 at 19:02