View on GitHub

Dystruct

Dystruct makes dynamical creation of c structures easy

Download this project as a .zip file Download this project as a tar.gz file

Dystruct

Abstract

Dystruct is a little C-Library that lets you easily build your own C-Structures at runtime.

If you, for example, don't know which kinds of structures you have to pass to a dynamically called function (with libffi), you'll have to build them on the heap at runtime. This library does just that while taking care of the correct alignment requirements of the members.

Introduction

As an use case example, consider the following code:

struct flat {
    int a;
    double b;
    char c;
};

[...]

int do_sth(void){
    struct flat *s = malloc(sizeof(struct flat));
    s->a = 42;
    s->b = 424242.424242
    s->c = '*';

    return 0;
}

The structure s pointing to now lays on the heap and looks like this:

Offset: 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 
        +-----------+-----------+-----------------------+-
        |    42     |  padding  |    424242.424242      |-
        +-----------+-----------+-----------------------+-
Offset: 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
       -+--+--------+-----------+
       -|* |     padding        |
       -+--+--------+-----------+

As you can see, the cells 4 to 7 contain meaningless bytes filling up the space between the member "a" and "b" of the recently defined structure "flat". This is because the primitive type double has an alignment requirement of 8, meaning that a double value can only start at an offset which is a multiple of 8. The reason for this behaviour is very simple: Performance!

If the wordsize of an architecture is, for example, 8 bytes, you wouldn't want the value of a double type begin at offset 7 and end at 15, because this would force the processor to load two words (each one 8 bytes big) into some working registers. However, if all double values were properly aligned, every access to them could be done in just one cpu cycle. see also

Ok, now I know some of the internal mechanisms of data structure alignment. But what do I need your library for?

A very good question!

Consider the following scenario: You are building an interpreter for a programming language that reads commands from the console and executes them as the user types enter. (Python is such a programming language for example). Now you want the users of your interpreter to be able to use native C-Functions from within the language. This is very possible and there is even a library that enables you to load and call arbitrary functions at runtime, without compiling and linking against libraries which contain them. (libffi provides such functionality) While this would be sufficient for functions taking only values of primitive types, you, the programmer of the interpreter, would run into some severe problems when it comes to functions taking merely a pointer to a structure laying on the heap. What do you do? You can't use C-Constructs like

strcut foo *f = malloc(...);
call_func(funcpointer, f);

because you don't have access to the structure definition and thus cannot rely on the compiler to do the things just right.

This is the point when it comes to this little library. With it, the code above could be rewritten as follows:

uint32_t i1 = 42;
double d = 424242.424242;
uint8_t c1 = '*'

struct dstru_struct *ds1;

dstru_add_uint32(DYN_S_UINT32, (void *) &i1, ds1);
dstru_add_double(DYN_S_DOUBLE, (void *) &d, ds1);
dstru_add_uint8(DYN_S_UINT8, (void *) &c1, ds1);
dstru_finalize(ds1) == 0;

ds1 contains a member named "buffer", which is just a memory field. This field now contains the exact same data as the initialized structure s in our first example, including both padding byte sections.

Dependencies

You should have installed the unit testing framework Cunit, which the test suite will need to build correctly. However, it is possible to build the library without the test, although make will then end with an error code because of the lack of cunit.

On Mac OS X and some Linux distros, the filename of the Cunit main header slightly differs. But don't worry! The buildsystem takes care of this inconvenience for you.

Configuration

The configure script provides the following additional command line options.

With these options you can adjust the platform specific alignment requirements for the host you'll be using the library. Notice that you should only use powers of two as values for [integer]!

Installation

Just use these commands:

$ ./configure [option=value] ...
$ make && make check
$ make install

Development

Build system

After a fresh checkout of the repository, just execute the following command:

$ autoreconf --install

This will prepare the build system for your usage.

Silent make rules

If you rather appreciate silent (or more silent) build processes, you can run the configure script as follows:

$ ./configure --enable-silent-rules

While this does not completely silence the build, most of the commands executed by make rules won't be shown anymore. Make will still output cd messages, though.

Bugs

If you find a bug, please report it to the maintenance mail address (see ChangeLog), or submit an issue here on github.

Porting

The main porting adjustments are intended to be made in the file include/dstru_defines.h. If you've successfully ported the library to your platform, please send a patch, a pull request or a personal message. I'd then like to include your contribution in the upstream.