views:

127

answers:

4

I am making a memory block copy routine and need to deal with blocks of raw memory in efficient chunks. My question is not about the specialized copy routine I'm making, but in how to correctly examine raw pointer alignment in C.

I have a raw pointer of memory, let's say it's already cast as a non-null char *. In my architecture, I can very efficiently copy memory in 64 byte chunks WHEN IT IS ALIGNED TO A 64 BYTE chunk. So the (standard) trick is that I will do a simple copy of 0-63 bytes "manually" at the head and/or tail to transform the copy from an arbitrary char* of arbitrary length to a 64 byte aligned pointer with some multiple of 64 bytes in length.

Now the question is, how do you legally "examine" a pointer to determine (and manipulate) its alignment? The obvious way is to cast it into an integer and just examine the bits:

char *pointer=something.
int p=(int)pointer;
char *alignedPointer=(char *)((p+63)&~63);

Note here I realize that alignedPointer doesn't point to the same memory as pointer... this is the "rounded up" pointer that I can call my efficient copy routine on, and I'll handle any other bytes at the beginning manually.

But compilers (justifiably) freak out at casting a pointer into an integer. But how else can I examine and manipulate the pointer's lower bits in LEGAL C? Ideally so that with different compilers I'd get no errors or warnings.

+7  A: 

For integer types that are large enough to hold pointers, C99 stdint.h has:

For data lengths there are:

which have been around since well before C99.

If your platform doesn't have these, you can maximise your code's portability by still using these type names, and making suitable typedefs for them.

Craig McQueen
+1 beat me to it.
Richard Pennington
ah, but how does one get an *aligned* pointer from an un-aligned one?
JustJeff
A: 

Instead of int, try a datatype that's guaranteed to be the same size as a pointer (INT_PTR on Win32/64). Maybe the compiler won't freak out too much. :) Or use a union, if 64-bit compatibility is not important.

Seva Alekseyev
+1  A: 

I don't think that in the past people were as reluctant to do their own bit-banging, but maybe the current "don't touch that" mood would be conducive to someone creating some kind of standard library for aligning pointers. Lacking some kind of official api, you have no choice but to AND and OR your way through.

JustJeff
+1 In the past, there was no such thing as *undefined behavior*. If your compiler did what you wanted it to do, that was enough.
Richard Pennington
A: 

Casting pointers to and from integers is valid, but the results are implementation-defined. See section 6.3.2.3 of the standard. The intention seems to be that the results are what anybody familiar with the system would expect, and indeed this appears to be routinely the case in practice.

If the architecture in question can efficiently manipulate pointers and integers interchangeably, and the issue is just whether it will work on all compilers for that system, then the answer is that it probably will anyway.

(Certainly, if I were writing this code, I would think it fine as-is until proven otherwise. My experience has been that compilers for a given system all behave in very similar ways at this sort of level; the assembly language just suggests a particular approach, that all then take.)

"Probably works" isn't very good general advice though, so my suggestion would be just write the code that works, surround it enough suitable #ifdefs that only the known compiler(s) will compile it, and defer to memcpy in other cases.

#ifdef is rarely ideal, but it's fairly lightweight compared to other possibilities. And if implementation-defined behaviour or compiler-specific tricks are needed then the options are pretty limited anyway.

brone
"the assembly language just suggests a particular approach"-- I'm just going to start using this phrase in software debates, regardless of applicability.
notJim