11

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...

MADgood
  • 143
  • 1
  • 1
  • 8
  • I would use uint64_t instead from stdint.h – sambowry Dec 04 '09 at 06:22
  • 2
    uint64_t would be too big if your platform has less than 64-bit pointers. Use intptr_t and uintptr_t from the same header. – Todd Gamblin Dec 04 '09 at 06:24
  • @sambowry - Looks like you need to go through `stdint.h` a little closer. – Chris Lutz Dec 04 '09 at 06:25
  • If your expecting to use it as a 64-bit bitfield, then compiling for a 32-bit platform is going to break things no matter what you cast it to. As I mentioned in my answer below, you want to declare a union of the pointer with whatever sized bitfield you need, so the field is the correct size regardless of what platform you target. – Anon. Dec 04 '09 at 07:05
  • Why would you need such pointer manipulations in the first place? Their only legitimate use is for alignment purposes, and that has workarounds that don't require casting from and to integers. – CAFxX Dec 26 '11 at 13:33

4 Answers4

17

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
  • 73,191
  • 16
  • 130
  • 183
  • 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 Dec 04 '09 at 13:42
  • @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 Dec 05 '09 at 03:31
  • 1
    Could you explain the difference(s) between `intptr_t` and `uintptr_t`? – DRz Jun 08 '16 at 14:27
8

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.

Todd Gamblin
  • 58,354
  • 15
  • 89
  • 96
  • 4
    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 Dec 04 '09 at 06:29
3

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
  • 4,268
  • 1
  • 18
  • 16
  • 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 Dec 04 '09 at 19:54
  • 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 Dec 05 '09 at 09:27
  • -1 for preaching to the OP. Sounds like he knows what he wants. – Heath Hunnicutt Jul 06 '10 at 07:42
2

Declare a union of the pointer and a bitfield.

Anon.
  • 58,739
  • 8
  • 81
  • 86
  • 1
    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. – Todd Gamblin Dec 04 '09 at 06:31
  • 1
    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. Dec 04 '09 at 06:56