Programming Pointers

Computing properly aligned pointer values

Dan Saks

11/1/2009 12:00 AM EDT

A couple of months ago, I explained a technique that C++ run-time systems may use to dynamically allocate and deallocate arrays whose elements are class objects with constructors and destructors.1 I also showed how you can implement essentially the same behavior in C by writing your own array allocation and deallocation functions.

I ended that column by explaining that my implementation of those C functions will work just fine on any processor in which no type has an alignment stricter than that of size_t. However, it could produce undefined behavior on any machine with more strictly aligned types. This month, I'll explain why, and what you can do about it.

Rewinding just a little
As in my previous column, I'll illustrate the problem by using arrays of widgets. In C++, widget is a class defined with a default constructor, a destructor, and an assortment of other members (both functions and data). In C, a widget is a struct:

typedef struct widget widget;
struct widget
    {
    // ...
    };

along with functions that serve as the constructor and destructor:

void widget_construct(widget *pw);
void widget_destroy(widget *pw);

as well as other "member" functions.

In C++, you use an array new-expressions such as:

pw = new widget [n];

to allocate an array with n properly initialized widgets. In C, you can emulate the behavior of this array new-expression by implementing a function named new_widget_array and calling it in an expression such as:

pw = new_widget_array(n);

In C++, you use an array delete-expression such as:

delete [] pw;

to deallocate an array previously allocated by an array new-expression. In C, you can mimic the behavior of this array delete-expression by implementing a function named delete_widget_array and calling it in an expression such as:

delete_widget_array(pw);

Whereas the array dimension appears explicitly in each array new-expression, it never appears in an array delete-expression. Each array delete-expression has to obtain the array dimension another way. A common technique for passing the array dimension to the delete-expression is for the array new-expression to stash the array dimension in a location just before the array itself. Last month, I explained this technique by showing implementations of new_widget_array and delete_widget_ array that use it.

Inasmuch as the additional allocated storage holds an array dimension, it should be declared as type size_t, the same as the parameter to new_widget_array. Thus, new_widget_array should allocate storage for the array dimension along with the array itself using:

size_t size = sizeof(size_t) + n * sizeof(widget);
size_t *ps = (size_t *)malloc(size);

If ps is non-null (because malloc has returned a pointer to the requested storage), then new_widget_array can proceed to place the array dimension at the beginning of that storage:

*ps = n;

and then compute the address of the first element in the array itself:

++ps;

The allocated array is an array of widgets, but ps is a pointer to a size_t, so new_widget_array needs a cast (as part of an assignment) to obtain a pointer it can use to access the initial array element:

pw = (widget *)ps;

In my implementation of new_widget_array, I combined the increment and the assignment:

++ps;
pw = (widget *)ps;

into one expression:

pw = (widget *)++ps;

In the following discussion, it'll be easier to discuss the behavior if I keep the increment and assignment as two separate expressions.


Next:




D_Lundin

11/2/2009 7:37 AM EST

To stir up some discussion... wouldn't the following be an acceptable implementation of the same?

Assume that I know that my widget is a small one, maybe small enough to even fit inside a the minimum alignment. Lets say it is a C struct with a few integers in it, something like this:

struct widget
{
uint8_t x;
uint8_t y;
};

It would then be easiest to simply make the widget like this:

typedef union
{
size_t size;

struct widget
{
/* members */
};
} Widget_t;

size_t size = n * sizeof(Widget_t);
Widget_t *ps = (Widget_t*) malloc(size);

ps->size = n;
pw = (Widget_t*) ++ps;


The above code relies solely on "struct padding" (or union padding if you will), ie the padding is decided automatically by the compiler based on the alignment requirements, and appended to the end of the struct/union. This padding is something we can be sure is present on every system, if the system requires memory alignment.

With this method we don't have to worry about pointer casts nor to find the maximum alignment of the system manually: the code becomes easier to read. The only drawback with the above is if the widgets are large. It will then be a waste of memory to store only the size in one such a large memory area.

Thoughts? :)

Sign in to Reply



E111

11/6/2009 6:36 PM EST

I would probably go with something like this:

typedef struct {
// widget definition...
} widget_t;

typedef struct {
int count;
widget_t index_0;
} widget_array_alloc_header_t;


Then in new_widget_array:
widget_t *new_widget_array(int count){
size_t size = sizeof(widget_array_alloc_header_t) + (count-1)*sizeof(widget_t);

widget_array_alloc_header_t *ps = malloc(size);
ps->count = count;

return &ps->index_0;
}


If you do that won't the compiler correctly align/pad the widget_array_alloc_header_t structure such that the index_0 member is on the appropriate boundary.

Then all the following elements should equally be correctly aligned?

Sign in to Reply



D_Lundin

11/9/2009 7:24 AM EST

Yeah it will be correctly aligned, but... why would you want the count variable allocated for each element? The code looks the same as mine except that you replaced union with struct. Perhaps you meant to allocate the header separately from the array of data?

Either version will have the same advantage however: portable, automatic alignment calculation done by the struct padding.

Sign in to Reply



D_Lundin

11/9/2009 7:31 AM EST

> Perhaps you meant to allocate the header separately from the array of data?

I just realized this is exactly what you do, but in the same line of code :)

The "gap" between the header and the array should be handled by struct padding in your example as well, as sizeof() includes the number of padding bytes. A bit prettier than my example indeed.

Sign in to Reply



Please sign in to post comment

Navigate to related information

Datasheets.com Parts Search

185 million searchable parts
(please enter a part number or hit search to begin)
Jobs sponsored by

Feedback Form