1

If we start from AoS layout, AoS structs can be easily initialized as such:

struct Position { float x; float y; };

struct Position positions[] = {
     { .x = 1.f, .y = 2.f },
     { .x = 20.f, .y = 30.f },
     { .x = 150.f, .y = 200.f },
     { .x = 1000.f, .y = 2000.f },
};

The data is always grouped as I want, two values in each AoS struct. In memory it looks like:

| 1.f 2.f | 20.f 30.f | 150.f 200.f | 1000.f 2000.f |

If I swap it to SoA layout, SoA data can be just as easily initialized as such:

float position_x[] = { 1.f, 20.f, 150.f, 1000.f },
float position_y[] = { 2.f, 30.f, 200.f, 2000.f };

This data is always grouped as I want it to be, one value in each SoA array. In memory it looks like:

| 1.f 20.f 150.f 1000.f |
| 2.f 30.f 200.f 2000.f |

When it comes to AoSoA layout, it works if the width is fixed, here [2]:

struct Position { float x[2]; float y[2]; };

struct Position positions[] = {
    { .x = { 1.f, 20.f },
      .y = { 2.f, 3.f } },
    { .x = { 150.f, 1000.f },
      .y = { 200.f, 2000.f } },
};

The grouping here is 2 pairs [2] of 2 values (x,y) in each AoSoA struct. In memory it looks like:

| 1.f 20.f | 150.f 1000.f |
| 2.f 30.f | 200.f 1000.f |

But if I want to change the width to [4], the previous code leaves the AoSoA structs half 'empty'. A AoSoA width of [4] is meant to be used as 4 pairs [4] of 2 values (x,y), but the previous code will still only give me 2 pairs of 2 values in the lower parts of each AoSoA struct, leaving the upper slots of the subarrays empty (initialized to zero). Like this:

| 1.f 20.f ZERO ZERO | 150.f 1000.f ZERO ZERO |
| 2.f 30.f ZERO ZERO | 200.f 1000.f ZERO ZERO |

If I want my data to stay grouped such that all [4] spaces of the subarrays are filled with my data, I have to rewrite the initializer like this:

struct Position { float x[4]; float y[4]; };

struct Position positions[] = {
    { .x = { 1.f, 20.f, 150.f, 1000.f },
      .y = { 2.f, 3.0f, 200.f, 2000.f } },
};

And in memory, it will look like this:

| 1.f 20.f 150.f 1000.f |
| 2.f 30.f 200.f 1000.f |

If I change the width of my AoSoA, zeros start showing up in the data, but I want no zeros. I want the data to stay tightly grouped no matter what the width of the AoSoA is. I'm searching for a way to write my initializer such that the data will stay grouped automatically.

Is there a way that would allow me to have an initializer list for my AoSoA data such that I can change the width of the AoSoA and get the desired behavior?

5
  • All you examples may have padding in the struct, so none of them is guaranteed to be packed. You should use a compiler pragma to guarantee struct packing. Commented Jul 14, 2023 at 7:59
  • But it feels like you are not asking about struct packing, if you have less elements in your initializer list than the length of the array they will be initialized to 0, does that answer your question? Commented Jul 14, 2023 at 8:06
  • @Fredrik Right, I should use pragmas to guarantee that my structs are packed, thanks for mentioning it! But also yes, I used the term packing to mean something else than packing of structs and I see how that's confusing now. I will try to rephrase that better. What I meant rather is grouping. I want my values to stay grouped together without leaving zeroes in-between like in my example automatically, such that I don't have to rewrite the initializer everytime to keep the data grouped. Commented Jul 14, 2023 at 13:55
  • You shouldn't pack your structs if you really don't need it for serialization, packing structs have a performance hit. I'm still not really sure of the problem, your last example should work, even if you increase the size the same values will be set on the same elements. However, if you want a more flexible solution maybe have some init code that fills your array with the desired data depending on the size. Commented Jul 14, 2023 at 14:14
  • @Fredrik I updated the question to try to make the problem more clear. The init code is indeed what I might end up having to do. What I was hoping to find is some esoteric C trick that would make it work, such that it is done at compile time automatically for me. Commented Jul 14, 2023 at 14:34

1 Answer 1

1

The rule for partial initializers in the C language is that all remaining objects are initialized as if assigned 0, 0.0 or NULL (depending on type, and recursively). So no, if you declare the array larger than the number of initializers you provide, you will always get the rest assigned with 0.

You might be able to use dynamic memory allocation (e.g. malloc) if you don't know at compile time, how big your arrays will be.

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

Comments

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.