开发者

Can I 'extend' a struct in C?

开发者 https://www.devze.com 2023-04-03 18:22 出处:网络
typedef struct foo_s { int a; } foo; typedef struct bar_s { foo; int b; } bar; Essentially I want to do: bar b;
typedef struct foo_s {
    int a;
} foo;

typedef struct bar_s {
    foo;
    int b;
} bar;

Essentially I want to do:

bar b;
b.a;

I know that i could do b.foo_name.a if I had named the foo struct in bar, but Id prefer not to.

Any way to do this?

This question has gotten a variety of different answers, so let me explain the need. The reason I want to do this is because I have a library which I need to adapt to my situation, meaning that I cant modify the original struct decleration. Furthermore, all I need to do is add 1 item to the beginning of the struct (why the beginning? because I have an 'object' struct which heads all the s开发者_如何学JAVAtructs in the project). I could simply embed the struct like you mention but its REALLY annoying as all references will need to be typed 'variable->image.location' that 'image.' typed a billion types is really annoying.


Evidently this feature has been added to C11, but alas I don't have access to a C compiler of recent vintage (>= GCC 4.6.2).

typedef struct foo {
  int a;
} foo;

typedef struct bar {
  struct foo;
  int b;
} bar;

int main() {
  bar b;
  b.a = 42;
  b.b = 99;
  return 0;
}


You can, using pointers, because a pointer to a structure object is guaranteed to point its first member. See e.g. this article.

#include <stdlib.h>
#include <stdio.h>

typedef struct foo_s {
    int a;
} foo;

typedef struct bar_s {
    foo super;
    int b;
} bar;

int fooGetA(foo *x) {
  return x->a;
}

void fooSetA(foo *x, int a) {
  x->a = a;
}

int main() {
  bar* derived = (bar*) calloc(1, sizeof(bar));
  fooSetA((foo*) derived, 5);
  derived->b = 3;
  printf("result: %d\n", fooGetA((foo*) derived));
  return 0;
}


Not possible in C the way you did. But you can mimic inheritance having a foo member variable in bar.

typedef struct bar_s {
    foo obj;
    int b;
} bar;

bar b;
b.obj.a = 10;


If you ment

typedef struct foo_s {
    int a;
  } foo;

typedef struct bar_s {
 foo my_foo;
int b;
} bar;

so you can do:

bar b; b.my_foo.a = 3;

Otherwise, There's no way of doing it in C since the sizeof(bar_s) is detriment on compile time. It's not a good practice but you can save a void * ptr; pointer within bar_s, and another enum which describes the ptr type, and cast by the type.

i.e:

typedef enum internalType{
  INTERNAL_TYPE_FOO = 0,
}internalType_t;

typedef struct bar_s {
 internalType_t ptrType;
 void* ptr;
int b;
} bar;

and then:

bar b;  foo f;
b.ptrType = INTERNAL_TYPE_FOO;
b.ptr = &f;

and some where else in the code:

 if (b.ptrType == INTERNAL_TYPE_FOO) {
    foo* myFooPtr = (foo *)b.ptr;
 }


It can be easily done via preprocessor:

Create a file named base_foo.h:

int foo;

Then simply include it:

typedef struct foo_s {
    #include "base_foo.h"
} foo;

typedef struct bar_s {
    #include "base_foo.h"
    int b;
} bar;


There is a confusion between anonymous structures and unions with nameless field. The nameless field is a Microsoft Extension.

struct known {
    struct /* anonymous */ {
        int anonymous;
    };
    int known;
};

An anonymous struct or union is a struct or union without any tag name that is embedded within another struct or union. It does not need to have any field names either.

A nameless field is a Microsoft Extension that allows limited inheritance in C.

struct A {
    int a;
};

struct B {
    struct A: // nameless field
    int b;
};

Anonymous struct or union are not Nameless Fields, and Nameless Fields are not Anonymous, at least the way C11 standard defines it.


You can try using inheritance:

struct foo_s
{
    int a;
};

struct bar_s: foo_a
{
    int b;
};

Works in C++, not sure if it works in C.


This is the simplest way without the c flags

#include <stdio.h>

#define foo_s struct { int a; }
typedef foo_s foo;

typedef struct bar_s {
    foo_s; // extends foo_s
    int b;
} bar;

int main(void)
{
    bar b = {
        .a = 1,
        .b = 2,
    };
    foo *f = (foo *)&b;

    printf("a: %d\n", f->a);

    return 0;
}
$ gcc inherit.c
$ ./a.out
a: 1
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号