Alignment of a structure.

T

Thomas Troeger

Hello,

I guess everyone is familiar with alignment issues in C. I have run over
a problem where I have two solutions and I would like comments on which
method is better. The problem: Copy (and later access) a structure at an
arbitrary memory location (we can assume there are no size constraints).
The memory could be a database page or something similar.

Here's some example code:
=======================================================================
#include <stdio.h>
#include <string.h>

typedef struct {
int i;
char c;
} foobar_t;

/* align address to be a multiple of n. */
void* align(void* memory, int n)
{
unsigned char* ptr;
unsigned int r;

ptr=(unsigned char*)memory;
r=(unsigned int)ptr%n;

return r ? ptr+n-r: ptr;
}

/* get integer member of foobar_t structure from memory. */
int get_i(void* memory)
{
foobar_t fb;

memcpy(&fb, memory, sizeof(fb));

return fb.i;
}

/* get integer member of aligned foobar_t structure from memory. */
int get_i_aligned(void* memory)
{
return ((foobar_t*)align(memory, sizeof(int)))->i;
}

/* copy foobar to memory location without alignment. */
void store_foobar(void* memory, const foobar_t* fp)
{
memcpy(memory, fp, sizeof(fp));
}

/* copy foobar to memory location with alignment. */
void store_foobar_aligned(void* memory, const foobar_t* fp)
{
store_foobar(align(memory, sizeof(int)), fp);
}

int main(int argc, char* argv[])
{
foobar_t fb={ 42, 'x' };
char buffer[64];

/* unaligned. */
store_foobar(buffer+5, &fb);
printf("%d\n", get_i(buffer+5));

/* aligned. */
store_foobar_aligned(buffer+5, &fb);
printf("%d\n", get_i_aligned(buffer+5));

return 0;
}
=======================================================================

Question #1: Which method is better? memcpy to a stack variable and
accessing members there, or aligning addresses and using direct access?

Question #2: I've scanned through google, Stroustrup and kernel sources
and haven't found an alignment function or macro. How can function
`align()' be implemented better? How can I find a reasonable alignment
boundary for the architecture I'm on (I've cruedly assumend `int')?

Answers and pointers/links to more information would be pretty cool!

Cheers,
Thomas.
 
A

Army1987

Thomas said:
Hello,

I guess everyone is familiar with alignment issues in C. I have run over
a problem where I have two solutions and I would like comments on which
method is better. The problem: Copy (and later access) a structure at an
arbitrary memory location (we can assume there are no size constraints).
The memory could be a database page or something similar.

Here's some example code:
=======================================================================
#include <stdio.h>
#include <string.h>

typedef struct {
int i;
char c;
} foobar_t;

/* align address to be a multiple of n. */
void* align(void* memory, int n)
I would prefer n to be a size_t, YMMV.
{
unsigned char* ptr;
unsigned int r;

ptr=(unsigned char*)memory;
r=(unsigned int)ptr%n;
Note that conversion to unsigned int is implementation-defined, and could
have undefined behavior if a pointer is larger than an unsigned int.
If you have <stdint.h>, you can use uintptr_t, and yet it's not guaranteed
that (uintptr_t)ptr is divisible by n only if ptr is aligned on n bytes
boundary.
return r ? ptr+n-r: ptr;
}

/* get integer member of foobar_t structure from memory. */ int
get_i(void* memory)
{
foobar_t fb;

memcpy(&fb, memory, sizeof(fb));
Why not just ((foobar_t *)memory)->i ?
return fb.i;
}

/* get integer member of aligned foobar_t structure from memory. */ int
get_i_aligned(void* memory)
{
return ((foobar_t*)align(memory, sizeof(int)))->i;
Alignment requirements are implementation defined.
}

/* copy foobar to memory location without alignment. */ void
store_foobar(void* memory, const foobar_t* fp) {
memcpy(memory, fp, sizeof(fp));
}

/* copy foobar to memory location with alignment. */ void
store_foobar_aligned(void* memory, const foobar_t* fp) {
store_foobar(align(memory, sizeof(int)), fp);
}

int main(int argc, char* argv[])
{
foobar_t fb={ 42, 'x' };
char buffer[64];

/* unaligned. */
store_foobar(buffer+5, &fb);
printf("%d\n", get_i(buffer+5));

/* aligned. */
store_foobar_aligned(buffer+5, &fb);
printf("%d\n", get_i_aligned(buffer+5));

return 0;
}
=======================================================================

Question #1: Which method is better? memcpy to a stack variable and
accessing members there, or aligning addresses and using direct access?
I don't see the point of the former.
Question #2: I've scanned through google, Stroustrup and kernel sources
and haven't found an alignment function or macro. How can function
`align()' be implemented better? How can I find a reasonable alignment
boundary for the architecture I'm on (I've cruedly assumend `int')?
As alignments are implementation defined, a NG about that architecture
would be a better place to ask.
 
A

Amandil

Hello, ....
Question #2: I've scanned through google, Stroustrup and kernel sources
and haven't found an alignment function or macro. How can function
`align()' be implemented better? How can I find a reasonable alignment
boundary for the architecture I'm on (I've cruedly assumend `int')?

Answers and pointers/links to more information would be pretty cool!

Cheers,
Thomas.

Responding to only your second question, and ignoring all notices to
the contrary (big orange signs "Don't go there"), I believe I've seen
some form of alignment issues in stdarg.h (which I don't have on my
computer now, I'm not sure why, must be implementation defined) as
something like:
(p is to be aligned to a multiple of sizeof int. The new value is
align.)

align = (p + (sizeof int - 1)) & ~(sizeof int - 1)

It's possible that the K&R2 implementation of malloc() might also have
some alignment code.

I hope this was helpful.

--- Marty
 
E

EventHelix.com

Question #2: I've scanned through google, Stroustrup and kernel sources
and haven't found an alignment function or macro. How can function
`align()' be implemented better? How can I find a reasonable alignment
boundary for the architecture I'm on (I've cruedly assumend `int')?

Answers and pointers/links to more information would be pretty cool!

The following link discusses byte alignment and ordering:

http://www.eventhelix.com/RealtimeMantra/ByteAlignmentAndOrdering.htm
 
W

William Ahern

Amandil said:
It's possible that the K&R2 implementation of malloc() might also have
some alignment code.

As far as hard-coded numbers go:
* BSD malloc implementations usually align on 16 byte boundaries.
* glibc-ptmalloc aligns on 8 byte boundaries.
* Perl XS allocator aligns on 4 byte boundaries (very annoying, definitely
broken on even common platforms Perl runs on).

Some common compilers support an alignof() operator. A poorer substitute
macro would something like:

#define alignof(type) offsetof(struct { char c; type t; }, t)

However, the compiler extension can operate on actual objects, rather than
just type names.

Finally, sizeof (type), will always give you a correct alignment as well.
But, as with the above macro, it might not give you the _minimum_ alignment.
 
T

Thomas Troeger

Dear all,

Thanks for the replies. I've created a set of macros that look like this:

#define ADDR_TYPE uintptr_t
#define ALIGN_MASK(type) (__alignof__(type)-1)
#define ALIGN_OFFSET(x, type) (((x)+ALIGN_MASK(type))&~ALIGN_MASK(type))
#define ALIGN_SIZE(x, type) ((x)&~ALIGN_MASK(type))
#define ALIGN(x, type) ((type*)ALIGN_OFFSET((ADDR_TYPE)(x), type))

Various tests show that they work as expected. Thanks! :)

Thomas.
 
K

Keith Thompson

Thomas Troeger said:
Thanks for the replies. I've created a set of macros that look like this:

#define ADDR_TYPE uintptr_t
#define ALIGN_MASK(type) (__alignof__(type)-1)
#define ALIGN_OFFSET(x, type) (((x)+ALIGN_MASK(type))&~ALIGN_MASK(type))
#define ALIGN_SIZE(x, type) ((x)&~ALIGN_MASK(type))
#define ALIGN(x, type) ((type*)ALIGN_OFFSET((ADDR_TYPE)(x), type))

Various tests show that they work as expected. Thanks! :)

I'm sure they work as expected on your system, and perhaps that's good
enough, but I've used systems on which the the representation of a
pointer is not just an integer (either signed or unsigned) on which
you can perform meaningful arithmetic.

The kinds of systems where you can run into problems include:

Cray vector systems, where a machine address points to a 64-bit
word and a C pointer stores the byte offset in the upper 3 bits.

Old x86 systems where a pointer consists of a segment number and
an offset. (Actually your methods might still work, as long as
the offset is in the low-order bits of the pointer, and as long as
you don't go outside the current segment.)

Other systems with segmented addressing schemes. I don't know of
any that are currently in common use.

Other systems (either past, present, or future) that use any
addressing scheme other than the simple monolithic linear scheme
used by most current systems.

I'm not saying you shouldn't use your macros, just that you should be
aware that they depend on things that aren't actually guaranteed by
the standard, and therefore aren't 100% portable. (Sometimes 99%
portability is good enough, sometimes it isn't.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top