0

I have a GSList from GTK/glib 2, and those only store full pointers, and I really don't want extra allocations. How do I do bit twiddling hacks to store extra data in those pointers?

I figure I can't just take a pointer and do tagged_ptr = ptr | 1 (indeed, the compiler complains very loudly when I try). I'm not sure how to do this.

This would definitely be local to a single function, however, and the GSList (or the pointers) would not leak onto the rest of the code.

SoniEx2
  • 1,864
  • 3
  • 27
  • 40
  • 1
    *and I really don't want extra allocations* Based on what actual **evidence**? – Andrew Henle Jun 27 '18 at 01:05
  • If it's local to one function then just use a variable on the stack. No allocation and surely more efficient than packing and unpacking pointers. – Retired Ninja Jun 27 '18 at 01:33
  • of course you can't do arithmetics like that because the only operation on pointers is adding with an integer. [You must cast to `(u)intptr_t` like this](https://stackoverflow.com/a/18426582/995714). And make sure that the pointers are at least 2-byte aligned so that you have the free lsb – phuclv Jun 27 '18 at 01:33
  • 3
    What problem are you trying to solve by avoiding *"extra allocations"*? See: [**What is the XY problem?**](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) Allocation within glib is notoriously generous, worrying about the allocation of a couple of pointers where the underlying library may have allocated 500 extra seems like an effort in futility. – David C. Rankin Jun 27 '18 at 01:56
  • 1
    To be clear, GLib does not make 500 extra allocations for each `GSList` element. Each `GSList` element is one heap allocation. Citation needed for “allocation within glib is notoriously generous”. – Philip Withnall Jun 27 '18 at 10:30

1 Answers1

2

To perform arithmetic on the numeric value of pointers (as opposed to pointer arithmetic, which is different and highly constrained), you need to cast back and forth to an appropriate integer type. If stdint.h defines UINTPTR_MAX, the appropriate type to use is uintptr_t. If not, there is no appropriate type, and your (nonportable) hack can't work on that particular implementation.

Note that you also have the problem that you're assuming pointers have low unused bits. If _Alignof(max_align_t) is greater than 1, this is probably a reasonable assumption, assuming the implementation follows the intent of the standard that the transformation to uintptr_t reflect the address model of the implementation (rather than being some arbitrary injection). But if not, you're out of luck.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • could I have two chars at the start of my struct (or rather a `char[2]`), always set them to specific values (say, 0 and 1), and take their pointers, to get portable tagged pointers? (then it's just a matter of, if it's 1, we offset by ptr-1, if it's 0 we don't do anything, either way we then convert/cast to a pointer to my struct?) – SoniEx2 Jun 28 '18 at 11:31