1

How can I have a struct declaration for each function, like the following:

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

struct additionalVariables;

struct container {
    int am;
    int bm;

    struct additionVariables *variables;
};

void foo(void) {
    struct container myContainer;

    struct additionalVariables {
        int x;
        int y;
    };

    myContainer.variables = malloc(sizeof(struct additionVariables));

    myContainer.variables->x = 5;
    myContainer.variables->y = 6;

    free(myContainer.variables);
}

void bar(void) {
    struct container myContainer;

    struct additionalVariables {
        char a;
        int b;
        int x;
    };

    myContainer.variables = malloc(sizeof(struct additionVariables));

    myContainer.variables->a = 5;
    myContainer.variables->b = 6;
    myContainer.variables->x = 7;

    free(myContainer.variables);
}

int main(void) {
    foo();
    bar();

    return 0;
}

I would prefer not to have to cast. Different additionVariables structs must be able to have the same names, for example both foo and bar need a property for x.

CHRIS
  • 957
  • 3
  • 10
  • 27
  • I think you're looking for a `union`. – Drew McGowen Aug 14 '14 at 20:55
  • Use a `void *` for `variables` member. – ouah Aug 14 '14 at 20:56
  • Can't use a union since I need to access it as myContainer.variables.x (so it would have to use C11 anonymous inheritance) but both need a property called x so that wouldn't work. My conditions are very specific, I'm not sure it's possible. Looking for closest answer. – CHRIS Aug 14 '14 at 20:58

4 Answers4

0

What you can do is to make local versions of the container structure.

void foo(void) {
    struct {
        int am;
        int bm;
        struct additionVariables {
            int x, y;
        } *variables;
    } myContainer;

    myContainer.variables = malloc(sizeof(struct additionVariables));
    myContainer.variables->x = 5;
    myContainer.variables->y = 6;

    free(myContainer.variables);
}

Then you can have the container structure declared with a void pointer if you need to pass it around.

struct container {
    int am;
    int bm;
    void *variables;
};

You will however still need to make a cast if you want to pass the object to some other function:

DoSomeThingWithContainer((struct container *)&myContainer);
wefwefa3
  • 3,872
  • 2
  • 29
  • 51
0

You can make container visible in your main but additionalVariables obviously can't be.
I Split it to several files and it compiles (and more importantly links) ok.

main.c

#include "foobar.h"

int main(void) {
    foo();
    bar();

    return 0;
}


foobar.h

void foo(void);
void bar(void);

struct additionalVariables;

struct container {
    int am;
    int bm;

    struct additionalVariables* variables;
};


foo.c

#include "foobar.h"

#include <stdlib.h>

struct additionalVariables {
    int x;
    int y;
};

void foo(void) {
    struct container myContainer;

    myContainer.variables = (additionalVariables*)malloc(sizeof(struct additionalVariables));

    myContainer.variables->x = 5;
    myContainer.variables->y = 6;

    free(myContainer.variables);
}


bar.c

#include "foobar.h"

#include <stdlib.h>

struct additionalVariables {
    int x;
    char a;
    int b;
};

void bar(void) {
    struct container myContainer;

    myContainer.variables = (additionalVariables*)malloc(sizeof(struct additionalVariables));

    myContainer.variables->a = 5;
    myContainer.variables->b = 6;
    myContainer.variables->x = 7;

    free(myContainer.variables);
}
ArnonZ
  • 3,822
  • 4
  • 32
  • 42
0

This is how I would solve the problem as presented:

struct container {
    int am;
    int bm;
};

You have not explained exactly why you needed the abstract pointer. So, I removed it.

void foo(void) {
    struct mycontainer {
        struct container base;
        int x;
        int y;
    } myContainer;

    myContainer.x = 5;
    myContainer.y = 6;
}

Here, foo() declares its local version of the container, adding additional fields. The address of myContainer.base can be passed to any function that wants a struct container *, and it would have the same address as a pointer to myContainer. Since we aren't dealing with pointers anymore, there is no need to call malloc() or free().

void bar(void) {
    struct mycontainer {
        struct container base;
        char a;
        int b;
        int x;
    } myContainer;

    myContainer.a = 5;
    myContainer.b = 6;
    myContainer.x = 7;
}

bar() can create its own version also.

int main(void) {
    foo();
    bar();

    return 0;
}

I have a feeling, however, that what you really want is dynamic dispatching.

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
0

Declare the struct externally with all of the names you need available in all branches:

struct additionalVariables {
    int x;
};

struct container {
    int am;
    int bm;
    struct additionalVariables *variables;
};

Then extend it within each function by placing the original as the first element of the greater struct:

void foo(void) {
    struct container myContainer;

    struct additionalVariablesFoo {
        struct additionalVariables base;
        int y;
    };

    myContainer.variables = malloc(sizeof(struct additionVariablesFoo));

    myContainer.variables.x = 5;
    (struct AdditionalVariablesFoo *)&(myContainer.variables)->y = 6;

    free(myContainer.variables);
}

Since it's always OK to cast down to the type of the first element, you'll be able to access the x field outside the function without a cast, at the cost of needing the cast to get at the y field within the function at init-time (obviously you don't need this cast either if you simply init it through a temporary variable of type struct AdditionalVariablesFoo *). Outside the function the extended object will be treated as having the type of its first element, the base where the shared names are declared.

Alex Celeste
  • 12,824
  • 10
  • 46
  • 89