Question

DISCLAIMER: This question is about a general concept. I've "dumbed down" the question so that I can ask it here clearly - without needing to provide the entire context of it's actual application. I can already foresee a bunch of comments like "why would you ever do that?" But, if the question could just be taken at face value, I'd appreciate it!

Suppose you wanted to dynamically synthesize some data structures in C at runtime out of some pre-defined structs.

The best way I know how to ask this question is through a code sample.

In the following, we've defined two structs: Foo and Bar. I also define a struct FooBar to illustrate at least one difference between the compile-time generated composite type and the runtime generated "dynamically synthesized" type.

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

typedef struct Foo {
    char junk1;
    char junk2;
} Foo;

typedef struct Bar {
    int junk3;
    int junk4;
} Bar;

typedef struct FooBar {
    Foo foo;
    Bar bar;
} FooBar;

int main()
{
    printf("Sizes: %li, %li, %li\n", sizeof(Foo), sizeof(Bar), sizeof(FooBar));
    // Prints: Sizes: 2, 8, 12
    // Because Foo is aligned on 1-byte boundaries and has total size of 2 bytes.
    // Bar is aligned on 4-byte boundaries and has total size of 8 bytes.
    // But FooBar is aligned on 4-byte boundaries due to the ints in Foo. Therefore,
    // the compiler added 2-bytes of padding after the foo member.

    // The following "works", but only allocates 10 bytes, and
    // "Bar" members are now "misaligned":
    void * syntheticFooBar = malloc(sizeof(Foo) + sizeof(Bar));
    ((Foo*)syntheticFooBar)->junk1 = 1;
    ((Foo*)syntheticFooBar)->junk2 = 2;
    ((Bar*)(syntheticFooBar + sizeof(Foo)))->junk3 = 3;
    ((Bar*)(syntheticFooBar + sizeof(Foo)))->junk4 = 4;

    free(syntheticFooBar);
    return 0;
}

So my questions would be:

1.) How badly would the lack of proper data alignment affect performance? Given the overhead involved with accessing "members" of the synthetic structures, is data-alignment even a significant contributing factor?

2.) Is there a better way of doing this given the constraints of run-time synthesis?

Était-ce utile?

La solution

1.) How badly would the lack of proper data alignment affect performance? Given the overhead involved with accessing "members" of the synthetic structures, is data-alignment even a significant contributing factor?

This is entirely dependent on the CPU architecture and compiler. On some systems you may just have a performance penalty, but on others you could get a crash.

2.) Is there a better way of doing this given the constraints of run-time synthesis?

Here's an example of how you might create a properly aligned synthesized struct at runtime:

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

typedef struct {
  char junk1;
  char junk2;
} A;

typedef struct {
  int junk3;
  int junk4;
} B;

typedef struct {
  double junk5;
  char junk6;
} C;

static size_t roundUp(size_t value,size_t factor)
{
  return value+factor-1-((value+factor-1)%factor);
}

#define alignof(type) (sizeof(struct {type a;char b;})-sizeof(type))

int main(int argc,char **argv)
{
  size_t offsets[3];
  size_t pos = 0;

  pos = roundUp(pos,alignof(A));
  offsets[0] = pos;
  pos += sizeof(A);

  pos = roundUp(pos,alignof(B));
  offsets[1] = pos;
  pos += sizeof(B);

  pos = roundUp(pos,alignof(C));
  offsets[2] = pos;
  pos += sizeof(C);

  {
    char *foobar = malloc(pos);
    A *a = (A *)(foobar + offsets[0]);
    B *b = (B *)(foobar + offsets[1]);
    C *c = (C *)(foobar + offsets[2]);
    a->junk1 = 1;
    a->junk2 = 2;
    b->junk3 = 3;
    b->junk4 = 4;
    c->junk5 = 5;
    c->junk6 = 6;
    free(foobar);
  }
  return 0;
}

The alignment of a particular struct is determined by creating a struct with the original struct and an extra char. The compiler will automatically add enough padding to make sure that the necessary alignment is preserved if you were to use an array of these structs, so by measuring the difference in sizes, we get the proper alignment.

Using the alignment information, we can create a table of where each member of the synthesized struct should live relative to the beginning. We just have to make sure that the position of each member has the proper alignment by rounding the position up to the nearest multiple of the alignment.

You should be able to generalize this to any number of members.

Note that if you wanted to determine the overall size if your synthesized struct (what sizeof() might return), so that you could create an array of these synthesized structs, then you need to get the combined alignment requirement and roundUp the final pos to that factor. The combined alignment will be the least common multiple of the individual alignments.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top