0

I want to convert this Python code:

outsides = [
    {   'baz': 7,
        'foobar': [   {'bar': 2, 'foo': 1},
                      {'bar': 4, 'foo': 3},
                      {'bar': 6, 'foo': 5}]},
    {'baz': 8}]

to C. I came up so far with this code:

#include <stdio.h>

struct Inside {
    int foo;
    int bar;
};

struct Outside {
    int baz;
    const struct Inside* foobar;
};

const struct Inside insides[] = {
    { .foo = 1, .bar = 2 },
    { .foo = 3, .bar = 4 },
    { .foo = 5, .bar = 6 },
};

const struct Outside outsides[] = {
    { .baz = 7, .foobar = insides },
    { .baz = 8, .foobar = NULL },
};

int main(int argc, char *argv[])
{
    printf("outsides: %i\n", sizeof(outsides) / sizeof(Outside));
    printf("insides: %i\n", sizeof(outsides[0].foobar));
    return 0;
}

But there are two problems:

  1. How do I inline the insides declaration in the outsides declaration?
  2. How can I determine the number of inside elements of the foobar member?

For question 2 I could implement some workarounds, like initializing the last element all with 0 and then looping over it and testing for all 0, or adding an additional count member in the Outside struct, but this doesn't look right. It would be perfect, if there could be another indirection: if the foobar member is an array of pointers to Inside elements, then I could just add a null pointer at the end.

Note: this is a simplified example which demonstrates the basic two questions I have, but I can't use a flexible array member, because there is more than one flexible array member in the Outside struct. And of course, the number of objects of the foobar member can vary. And I need a solution which works with C, not C++.

1
  • 4
    You have to decide how you're going to know how big the array is; C won't record the information for you. You can use a sentinel value, or explicitly record a count. Either way, you have to do it. C doesn't do anything behind the scenes for you. (So, IOW, you will need to use one of your 'workarounds' because there is no alternative to using a workaround.) Commented Oct 7, 2018 at 15:39

1 Answer 1

3

To answer question 1, since you've got designated initializers, you also have compound literals. However, to answer question 2, you have to tell your code how many entries are in the array pointed at by your pointer. C won't record the information for you. You can use a sentinel value, or explicitly record a count. Either way, you have to do it. C doesn't do anything behind the scenes for you. And, while you could nest the definition of struct Inside inside struct Outside, there's no scoping as in C++ to prevent you using struct Inside independently of struct Outside so there's no benefit to doing so — and I'd keep the structure definitions separate, as you have them.

So, you might use:

struct Inside
{
    int foo;
    int bar;
};

struct Outside
{
    int baz;
    size_t num_foobar;
    const struct Inside* foobar;
};    

const struct Outside outsides[] =
{
    { .baz = 7, .num_foobar = 3,
      .foobar = (struct Inside[]){
                    { .foo = 1, .bar = 2 },
                    { .foo = 3, .bar = 4 },
                    { .foo = 5, .bar = 6 },
      }
    },
    { .baz = 8, .num_foobar = 0, .foobar = NULL },
};

The last .num_foobar = 0 could be omitted since unspecified members are initialized to zero anyway, but I wouldn't recommend doing so. You can use int instead of size_t if you prefer. (The code above requires <stddef.h> or one of the other headers that defines size_t (such as <stdio.h>) – but with #include <stddef.h> added, it compiles to object code cleanly for me.)

I missed your request:

It would be perfect, if there could be another indirection: if the foobar member is an array of pointers to Inside elements, then I could just add a null pointer at the end.

That can be done with a type change in the structures and a bit more work in the initializer. I think the code above is quite a bit easier to understand, but what follows is not completely dreadful either.

#include <stddef.h>

struct Inside
{
    int foo;
    int bar;
};

struct Outside
{
    int baz;
    const struct Inside **foobar;
};    

const struct Outside outsides[] =
{
    { .baz = 7,
      .foobar = &((const struct Inside*[]){
                    &(struct Inside){ .foo = 1, .bar = 2 },
                    &(struct Inside){ .foo = 3, .bar = 4 },
                    &(struct Inside){ .foo = 5, .bar = 6 },
                    NULL,
                })[0],
    },
    { .baz = 8, .foobar = NULL },
};

While this is 'doable', I definitely prefer the first code.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, this looks perfect. I think I'll use the count member solution, because this could be a uint8_t (for my use case), which would even save some more bytes, and would save the additional array of pointers (I'm using this for a 6809 processor as the target, with gcc6809 and with 32 kB ROM and 1 kB RAM).
In your memory-constrained environment, the first solution is undoubtedly better for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.