22

I read that you can't do bitmasks on pointers, how come you can't do bitwise operations on pointers?

Is there any way to achieve the same effect?

Does the same apply to C++?

rubixibuc
  • 7,111
  • 18
  • 59
  • 98
  • I'm curious about your use case for this. Can you elaborate? – Simon Whitehead Apr 07 '13 at 21:58
  • 4
    What "effect" are you trying to achieve? Bit operations on pointers really don't make sense. – Keith Thompson Apr 07 '13 at 21:59
  • Most likely aligned allocation, which isn't really needed anymore anyway since the runtime generally provide the mechanics for you. – WhozCraig Apr 07 '13 at 21:59
  • @KeithThompson: Maybe you want to find page boundaries. – Dietrich Epp Apr 07 '13 at 22:02
  • @KeithThompson: You might also want to add pointer tags, e.g., if you're writing an interpreter. Or get a correctly aligned pointer from a misaligned one. – Dietrich Epp Apr 07 '13 at 22:04
  • On many systems memory addresses are multiple of `sizeof(word)`, which means that you can piggy back flags in the zeroed lsb. A trick of that sort is used in the runtime memory model of the OCaml language to avoid boxing integers through indirection (it's still a form of boxing though). – didierc Apr 07 '13 at 22:05
  • 1
    To expand on my previous comment, bit operations on pointers make no sense given what the language standard says about pointers. They might make sense for a given system -- and in that case, there are various tricks you can use, mostly involving casting. But your question and the answers would be more useful to future readers if you'd tell us exactly what you're trying to accomplish. Bit operations on pointers are not a goal, they're a means to accomplishing some other goal. What is that other goal? – Keith Thompson Apr 07 '13 at 23:33
  • I love the comments about how bitwise operations on pointers don't make any sense. Is your imagination really that bankrupt? – chili Mar 23 '16 at 16:45

3 Answers3

26

The reason you can't do bitwise pointer operations is because the standard says you can't. I suppose the reason why the standard says so is because bitwise pointer operations would almost universally result in undefined or (at best) implementation-defined behavior. So there would be nothing you could do that is both useful and portable, unlike simpler operations like addition.

But you can get around it with casting:

#include <stdint.h>

void *ptr1;
// Find page start
void *ptr2 = (void *) ((uintptr_t) ptr1 & ~(uintptr_t) 0xfff)

As for C++, just use reinterpret_cast instead of the C-style casts.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 2
    It's actually quite annoying. C, well known as the operating system and embedded system "high level" language of choice for decades now - both types of development which are fundamentally non-portable at the base level, still refuses to embrace the role it is now most suited for. Thankfully c99 finally recognizes a few of the hard integer types, there is no reason at all why memory management code has to cast every variable multiple times to do a simple mask operation. – duanev Oct 20 '15 at 03:51
  • @duanev On the plus side, most of the casting isn't actually costing anything at runtime. The compiler is almost definitely able to tell that you just want to modify the value, and at the CPU level there's no meaningful difference between a pointer and any other integer, so it almost definitely just does the arithmetic with no casting logic. – Nic Mar 21 '18 at 04:09
  • @duanev Yes. I don't see how that contradicts anything I said. – Nic Mar 27 '18 at 15:08
  • Why should I use reinterpret_cast instead of static_cast here? – NicoBerrogorry Apr 16 '18 at 22:03
  • @NicoBerrogorry: Because `static_cast` is incapable of casting `void *` to `uintptr_t` or vice versa. If you use `static_cast` your program should not even compile. – Dietrich Epp Apr 16 '18 at 23:05
  • I can confirm It does not compile on gcc 7.3... I can tell how It doesn't make sense though, and I feel silly now. Why would it allow you to cast a pointer to a type with more "freedom of operation", the restrictions on pointers are there for a reason... My bad – NicoBerrogorry Apr 16 '18 at 23:30
  • That's also the danger of reinterpret_cast() I guess... but at least it's easier to spot than C cast, which is no good in most scenarios – NicoBerrogorry Apr 16 '18 at 23:32
  • @NicoBerrogorry: It's not like `reinterpret_cast` is any more dangerous than doing bitwise arithmetic on a pointer, which is inherently dangerous to begin with. – Dietrich Epp Apr 16 '18 at 23:40
  • Yeah... I don't want to change the subject, but I finally came to the conclusion that cmp (x86 asm) was my best option anyways, so I don't even need bitwise arithmetic... – NicoBerrogorry Apr 17 '18 at 00:31
  • That's a bizarre alternative in a discussion about C. – Dietrich Epp Apr 17 '18 at 00:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/169125/discussion-between-nicoberrogorry-and-dietrich-epp). – NicoBerrogorry Apr 17 '18 at 03:40
8

It's disallowed because the semantics aren't really well defined. You can certainly do it, though. Just cast to uintptr_t, do the operations and then cast back into a pointer type. That will work in C++, too.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
5

You can't use bitwise operators on pointers because the standards impose very few requirements on how a pointer is represented and what range of values any particular pointer may address. So there's no definition of what it would mean to use those operators on a pointer.

Nevertheless, most compilers on most machines use the obvious mapping of the memory address as the value of the pointer. And most of those will let you cast a pointer to an integral type. You can then do bitwise operations on the value, and even cast it back to a pointer. But that won't be strictly portable or well-defined in general.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175