How to portably check *char alignment?

T

tbroberg

I have some pretty heavily optimized old code written to be nice and
portable in a 32-bit environment.

In places, it needs to check the lowest few bits of various pointers
for alignment.

Now I am porting this code to 64-bit environments including MS and
gcc, and whatever modern and near-future systems my customers and
customers-to-be are likely to run on.

I need to cast pointers of arbitrary size to any arbitrary integer
class with at least 3 bits of length and then look at those few bits.

What are some good options to do this portably?

My best idea so far is to cast to a ptr_diff_t. Seems like that would
have to be an integer type which would have a strong tendency to be te
same size as the pointer type.

How big are the problems with that?

Any better ideas?

Thanks,
- Tim.
 
A

Army1987

I have some pretty heavily optimized old code written to be nice and
portable in a 32-bit environment.

In places, it needs to check the lowest few bits of various pointers
for alignment.

Now I am porting this code to 64-bit environments including MS and
gcc, and whatever modern and near-future systems my customers and
customers-to-be are likely to run on.

I need to cast pointers of arbitrary size to any arbitrary integer
class with at least 3 bits of length and then look at those few bits.

What are some good options to do this portably?

My best idea so far is to cast to a ptr_diff_t. Seems like that would
have to be an integer type which would have a strong tendency to be te
same size as the pointer type.
1) It is ptrdiff_t, not ptr_diff_t.
2) It isn't *guaranteed* to be able to hold a pointer. If you have
C99, intptr_t in <stdint.h> is (but it isn't guaranteed to exist).
 
M

Michal Nazarewicz

I have some pretty heavily optimized old code written to be nice and
portable in a 32-bit environment.

In places, it needs to check the lowest few bits of various pointers
for alignment.

Now I am porting this code to 64-bit environments including MS and
gcc, and whatever modern and near-future systems my customers and
customers-to-be are likely to run on.

I need to cast pointers of arbitrary size to any arbitrary integer
class with at least 3 bits of length and then look at those few bits.

As far as I know there's a type intptr_t somewhere.
What are some good options to do this portably?

As far as I remember casting pointer into an integer is undefined or
unspecified or whatever behaviour so there is no portable way.

I guess you would be best creating a macro which would check the
alignment and redefine it for each platform your code have to work.
I suppose the following should work in most cases:

#define PTRALIGN(ptr) ((unsigned int)(ptr) & 7)
 
K

Keith Thompson

I have some pretty heavily optimized old code written to be nice and
portable in a 32-bit environment.

In places, it needs to check the lowest few bits of various pointers
for alignment.

Now I am porting this code to 64-bit environments including MS and
gcc, and whatever modern and near-future systems my customers and
customers-to-be are likely to run on.

I need to cast pointers of arbitrary size to any arbitrary integer
class with at least 3 bits of length and then look at those few bits.

What are some good options to do this portably?
[...]

There are none.

You can do it non-portably by, for example, casting the pointer to
some integer type (size_t? unsigned long?) and checking the low-order
bits, but I've worked on systems where this would not work.

On Cray vector systems, hardware addresses point to 64-bit words. The
C compiler builds pointers to 8-bit bytes (CHAR_BIT==8) by storing an
offset in the high-order bits of the word pointer. Thus a low-order
bit set to 1 merely means that it points to an odd *word*, not an odd
byte.

You're not likely to encounter such a system, and on every other
system I've used, examining the low-order bits of a pointer (after
casting it to an integer) will do the right thing.

Conversion from pointers to integers is implementation-defined, but is
"intended to be consistent with the addressing structure of the
execution environment" (C99 6.3.2.3, footnote).

My suggestion:

1. See if you can remove the dependency on pointer alignment. This
might not be possible.

2. Do the checks in the obvious way, but isolate the code and mark it
as non-portable. Do it in a way that you can modify the technique
for exotic architectures without damaging the rest of the code.

3. Write a test program that verifies that your technique actually
works on the current machine. For example, malloc() a small chunk
of memory:
p = malloc(16);
and confirm that p and p+4 are 4-byte aligned, but p+1, p+2, and
p+3 are not. If you can, integrate the test program (including
running it and checking the result) into your build process. It
would be nice if you could run the test program on an exotic
machine to confirm that it fails when it's supposed to, but that
could be difficult.
 
T

tbroberg

1) It is ptrdiff_t, not ptr_diff_t.
2) It isn't *guaranteed* to be able to hold a pointer. If you have
C99, intptr_t in <stdint.h> is (but it isn't guaranteed to exist).

Ok, I've defined a type that all the pointers get cast to, and set the
type to intptr_t.

This seems to work fine.

Thanks to all for the quick and expert advice.
- Tim.
 

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

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,266
Latest member
DavidaAlla

Latest Threads

Top