Newsletter

Industrial Control DesignLine  >  Design Center

Variations on a flexible array theme

Different dialects of C and C++ support different forms of flexible array members. Unfortunately, the more expressive forms are the less portable ones.

Page 1 of 3

Courtesy of Embedded.com

Some months ago, I described how C++ run-time systems dynamically allocate and deallocate arrays whose elements are class objects with constructors and destructors.1 I also showed how you can implement similar behavior in C by writing your own array allocation and deallocation functions.

More recently, I presented a technique you can use to ensure that the elements in dynamically allocated arrays are properly aligned.2 Unfortunately, under some conditions, that technique wastes a little storage. This month, I'll show you a different, arguably better, approach to solving such alignment problems, which avoids that waste.

What I'm about to show you is not just about eliminating a few bytes of unnecessary padding. It's been my observation that too many embedded systems developers lay out varying length structures as arrays of (unsigned) characters and compute offsets using ad hoc pointer arithmetic and casts. The resulting code is usually very brittle--hard to get right and easy to break. I think you're much better off using structures that lay out your data as accurately as possible, and let the compiler do the alignment and padding. The resulting code will be easier to read and maintain.

Where we were
As before, I'll illustrate the problem by using arrays of widgets. In C++, you use an array new-expression such as:

pw = new widget [n];

to allocate an array with n properly initialized widgets. In C, you can implement an allocation function named new_widget_ array and call 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 implement a deallocation function named delete_widget_array and call it in an expression such as:

delete_widget_array(pw);

Each call to delete_widget_ array passes only one argument: the base address of the allocated array. However, the function needs to know the array dimension as well. One way to solve this problem is for new_widget_array to stash the array dimension in a location just before each array that it allocates. Then delete_widget_array can use a little pointer arithmetic to locate and extract the array dimension residing just before the array to be deallocated.

The new_widget_array function uses the Standard C malloc function to allocate the dynamic storage. Each call to malloc must return a pointer that's aligned to the most strictly aligned object that could be placed in the allocated storage. If you allocate storage only for an array of widgets, the storage for the array elements will be properly aligned. However, as I explained in an earlier column, if you allocate storage for an array plus an additional integer to hold the array dimension, and you place that integer before rather than after the array, the array elements could be misaligned.

I suggested solving this problem by using a union defined as:

typedef union widget_array_header widget_array_header;
union widget_array_header
{
size_t size;
max_align_t unused;
};

where max_align_t is a type that's at least as strictly aligned as every other type.2 Instead of allocating storage for a size_t plus an array of widgets, the new_widget_array function should allocate storage for a widget_array_header plus the array, as shown in Figure 1.


Click on image to enlarge.

The size of the padding after the size_t member of the widget_array_header is the difference, if any, between sizeof(size_t) and sizeof(max_align_t).

Using the widget_array_header, the new_widget_ array function looks like the code in Listing 1.


Click on image to enlarge.

This approach avoids alignment errors. However, as I mentioned earlier, it might waste a little storage. In particular, if the alignment of widget is less than the alignment of max_align_t, the padding between the size_t object and the first widget array element in Figure 1 will be larger than necessary.

For example, suppose this code is compiled for a platform in which a size_t is a four-byte object with an alignment of four and a max_align_t is an eight-byte object with an alignment of eight. Then the size and alignment of the widget_array_header will be eight as well, and the first widget array element will have an offset at least eight bytes from the beginning of the allocated storage. However, if widget has an alignment of only four, forcing the first widget to an eight-byte boundary is overkill. It wastes four bytes.



Page 2: next page  

Page 1 | 2 | 3



Rate this article
WORSE | BETTER
1 2 3 4 5




Related Content

TECH PAPER
1. Industrial Fiber Optics in Train Transportation Systems

TECH PAPER
2. Developing Functional Safety Systems with TÜV-Qualified FPGAs

TECH PAPER
3. Enhancing Industrial Automation Solutions with Embedded Software: New Efficiencies and Faster Cycle Times

TECH PAPER
4. Lowering the Total Cost of Ownership in Industrial Applications

 


 Featured Jobs
Boeing seeking Senior Software Engineer in Annapolis Junction, MD

Emulex seeking Senior Program Manager in Costa Mesa, CA

Accenture seeking Data Center Technology in Reston, VA

Eurotech seeking Sales Executive in Amaro, Italy

NYU Langone Medical Center seeking IS Manager in New York, NY

More jobs on EETimesCareers
 Sponsor
 CAREER CENTER
Ready to take that job and shove it?
SEARCH JOBS:

 SPONSOR

 RECENT JOB POSTINGS
For more great jobs, career related news, features and services, please visit EETimes' Career Center.