views:

306

answers:

4

I'm in the middle of this C project that I wish to make very memory efficient. In several cases, I am using the void *s of a dynamic array structure I wrote in order to hold bits. I wish to use all 64 (in this case) bits.

I soon realized that you cannot actually do any bit manipulation on a pointer. So my solution was the following:

void *p;
((unsigned long)p) << 4;
((unsigned long)p) & 3;

This gets the job done, but only because on my computer, longs and pointers are equal in size. Will this be the case in all (or most) architectures?

And my real question: Is there a more correct way to do bit manipulation on a pointer? I had thought that this approach was somewhat common in C (packing bits into a void *), but I could be mistaken...

+8  A: 

If your compiler supports it, C99's <stdint.h> header provides the intptr_t and uintptr_t types that should be large enough to hold a pointer on your system, but are integers, so you can do bit manipulation. It can't really get much more portable than that, if that's what you're looking for.

Chris Lutz
Anyway, you probably don't need a fully portable solution. Any bit-twiddling that attempts to store flags in the lower bits of pointers is necessarily platform-specific, since it relies on assumptions about object alignment. So the questioner will probably have to do some work (or at least research) when porting to a new platform anyway.
Steve Jessop
@Steve - If he's doing bit twiddling on a pointer, I certainly hope he's not dereferencing it later. That just sounds like a portability nightmare. If he was doing that, I doubt he'd be asking about the portability of his operations.
Chris Lutz
+1  A: 

Declare a union of the pointer and a bitfield.

Anon.
You'd still need to know how big to make the bitfield, so your other field would need to be an intptr_t. I'm not sure whether this or casting would be more readable.
tgamblin
You make the bitfield as large as it needs to be for your other purposes. The compiler will then ensure that the struct is big enough so that the larger out of the pointer and bitfield fit in it. This situation is exactly what unions are for.
Anon.
+5  A: 

If you need to do this kind of manipulation on pointers, you can cast them to intptr_t and uintptr_t, both of which can be found in stdint.h. These are guaranteed to be defined as the platform-specific integer type with enough bits to hold a pointer.

There's also ptrdiff_t in there, if you need something to hold the difference between two pointers.

tgamblin
And if your compiler doesn't support stdint.h (*cough* Microsoft *cough*), the following SO answer and comments have links to several you might decide to use: http://stackoverflow.com/questions/126279/c99-stdint-h-header-and-ms-visual-studio/126285#126285
Michael Burr
+3  A: 

I think you're trying to solve the wrong problem. The real problem is right here:

I am using the void *s of a dynamic array structure I wrote in order to hold bits.

Don't use void pointers to hold bits. Use void pointers to hold pointers. Use unsigned integers to hold bits.

Secure
I'm not sure I'd agree that its practical to rewrite an entire data structure and all of its associated functions in order to be able to store non pointer values.Then again, perhaps if I had written my data structure more correctly I wouldn't have had this problem.
MADgood
Well, you can use Excel as a database if you want to avoid the additional work of learning about databases, but will it be a good idea in the long run? Be aware that pointer-to-int conversions and back are completely implementation defined, and if you are not carefull with the handling you may end in undefinded behaviour. Your structure was intended to store pointers. Why not write a BitStore datastructure specialized to store bits, with all the bit twiddling already inside, so you don't have to care for it on every call?
Secure
-1 for preaching to the OP. Sounds like he knows what he wants.
Heath Hunnicutt