337

What is uintptr_t and what can it be used for?

user16217248
  • 3,119
  • 19
  • 19
  • 37
dimba
  • 26,717
  • 34
  • 141
  • 196
  • 6
    Additional details on this type as well as other related types is available here: http://www.opengroup.org/onlinepubs/000095399/basedefs/stdint.h.html – Void - Othman Dec 04 '09 at 18:17
  • 2
    http://en.cppreference.com/w/cpp/types/integer lists `std::uintptr_t` and `std::intptr_t` a C++11 optional. – alfC Jun 27 '17 at 14:15

5 Answers5

302

First thing, at the time the question was asked, uintptr_t was not in C++. It's in C99, in <stdint.h>, as an optional type. Many C++03 compilers do provide that file. It's also in C++11, in <cstdint>, where again it is optional, and which refers to C99 for the definition.

In C99, it is defined as "an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer".

Take this to mean what it says. It doesn't say anything about size.

uintptr_t might be the same size as a void*. It might be larger. It could conceivably be smaller, although such a C++ implementation approaches perverse. For example on some hypothetical platform where void* is 32 bits, but only 24 bits of virtual address space are used, you could have a 24-bit uintptr_t which satisfies the requirement. I don't know why an implementation would do that, but the standard permits it.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 17
    Thanks for the "". My application didn't compile because of uintptr_t declaration. But when I read your comment I add "#include " and yeah now it works. Thanks! – JavaRunner Feb 12 '14 at 08:13
  • 4
    To [allocate aligned memory](http://stackoverflow.com/q/227897/183120), among other uses, for instance? – legends2k Jul 21 '15 at 07:36
  • 5
    Another common use case of casting a pointer to an int is to create an opaque handle that hides the pointer. This is useful for returning a reference to an object from APIs where you want to keep the object private to the library and prevent applications from having access to it. The application is then forced to use the API to perform any operations on the object – Joel Cunningham May 05 '16 at 13:57
  • 5
    @JoelCunningham: that works but isn't really any different from using `void*`. It affects possible future directions, though, especially if you might want to change to use something that really is just an integer handle, not a converted pointer at all. – Steve Jessop May 05 '16 at 14:19
  • 2
    @CiroSantilli烏坎事件2016六四事件法轮功 A common use case is to pass just an int to an API which expects a void* to generic data. Saves you the keystrokes `typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;`. Instead: `callback.dataPtr = (void*)val`. On the other side, you of course get `void*` and have to cast it back to `int`. – Francesco Dondi Apr 05 '17 at 12:09
  • The one in `` is in the `std` namespace, of course - it might be germane to mention that, as I commonly see code which assumes that `` necessarily declares the global-namespace version (which is permitted, but not required). – Toby Speight Feb 23 '23 at 17:11
260

uintptr_t is an unsigned integer type that is capable of storing a data pointer (whether it can hold a function pointer is unspecified). Which typically means that it's the same size as a pointer.

It is optionally defined in C++11 and later standards.

A common reason to want an integer type that can hold an architecture's pointer type is to perform integer-specific operations on a pointer, or to obscure the type of a pointer by providing it as an integer "handle".

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • 66
    Note that `size_t` only needs to be sufficient to hold th size of the largest object, and can be smaller than a pointer. This would be expected on segmented architectures like the 8086 (16 bits `size_t`, but 32 bits `void*`) – MSalters Dec 04 '09 at 09:08
  • 4
    for representing the difference between two pointers, you have `ptrdiff_t`. `uintptr_t` isn't meant for that. – jalf Dec 04 '09 at 14:44
  • 3
    @jalf: For difference, yes, but for *distance*, you would want an unsigned type. – Drew Dormann Dec 04 '09 at 17:00
  • 1
    uintptr_t definition is apparently not obligatory (so not standard) even in C++11! http://www.cplusplus.com/reference/cstdint/ (I got the hint from Steve Jessop answer) – Antonio Oct 01 '14 at 20:56
  • Can't regular unsigned ints (assuming they're at least as large as the size of your memory) store a pointer? after all, they're simply a numerical address to a block of memory... – MarcusJ May 31 '15 at 10:57
  • 2
    @MarcusJ `unsigned int` usually isn't large enough. But it might be large enough. This type exists specifically to remove all *"assuming"*. – Drew Dormann May 31 '15 at 16:46
  • Note, uintptr_t can hold ever value of every data pointer, but may not of every function pointer. (same as void*) – 12431234123412341234123 Mar 28 '16 at 16:43
  • 1
    @DrewDormann please make it more explicit that uintptr_t is available in C as well (say it briefly in your own words and give a quick link to Steve Jessop's answer). – brodybits Mar 07 '18 at 22:56
31

It's an unsigned integer type exactly the size of a pointer. Whenever you need to do something unusual with a pointer - like for example invert all bits (don't ask why) you cast it to uintptr_t and manipulate it as a usual integer number, then cast back.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 6
    Of course you could do that, but that would of course be undefined behavior. I believe then only thing you can do with the result of a cast to uintptr_t is to pass it on unchanged and cast it back - everything else is UB. – sleske Jan 13 '11 at 22:47
  • There are times where you need to play with the bits, and it would normally generate compiler errors. A common example is enforcing 16-byte aligned memory for certain video and performance critical applications. http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me – Cloud Jul 22 '14 at 21:48
  • 4
    @sleske that's not true. On machines that have self-aligned types the two least significant bits of a pointer are going to be zero (because addresses are multiples of 4 or 8). I've seen programs that exploit this to compress data.. – mrk Jan 03 '15 at 17:48
  • 3
    @saadtaame: I just pointed out that this is UB *according to the C standard*. That does not mean it cannot be defined on some systems - compilers and runtimes are free to define a specific behaviour for something that is UB in standard C. So there's no contradiction :-). – sleske Jan 03 '15 at 18:34
  • 8
    It's not necessarily exactly the size of a pointer. All the standard guarantees is that converting a `void*` pointer value to `uintptr_t` and back again yields a `void*` value that compares equal to the original pointer. `uintptr_t` is usually the same size as `void*`, but that's not guaranteed, nor is theree any guarantee that the bits of the converted value have any particular meaning. And there's no guarantee that it can hold a converted pointer-to-function value without loss of information. Finally, it's not guaranteed to exist. – Keith Thompson Sep 02 '17 at 20:28
  • One use is xor linked lists for example. – WENDYN Jul 22 '23 at 14:25
20

There are already many good answers to "what is uintptr_t data type?". I will try to address the "what it can be used for?" part in this post.

Primarily for bitwise operations on pointers. Remember that in C++ one cannot perform bitwise operations on pointers. For reasons see Why can't you do bitwise operations on pointer in C, and is there a way around this?

Thus in order to do bitwise operations on pointers one would need to cast pointers to type uintptr_t and then perform bitwise operations.

Here is an example of a function that I just wrote to do bitwise exclusive or of 2 pointers to store in a XOR linked list so that we can traverse in both directions like a doubly linked list but without the penalty of storing 2 pointers in each node.

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }
Graham Asher
  • 1,648
  • 1
  • 24
  • 34
BGR
  • 669
  • 5
  • 10
10

Running the risk of getting another Necromancer badge, I would like to add one very good use for uintptr_t (or even intptr_t) and that is writing testable embedded code.

I write mostly embedded code targeted at various arm and currently tensilica processors. These have various native bus width and the tensilica is actually a Harvard architecture with separate code and data buses that can be different widths.

I use a test driven development style for much of my code which means I do unit tests for all the code units I write. Unit testing on actual target hardware is a hassle so I typically write everything on an Intel based PC either in Windows or Linux using Ceedling and GCC.

That being said, a lot of embedded code involves bit twiddling and address manipulations. Most of my Intel machines are 64 bit. So if you are going to test address manipulation code you need a generalized object to do math on. Thus the uintptr_t give you a machine independent way of debugging your code before you try deploying to target hardware.

Another issue is for the some machines or even memory models on some compilers, function pointers and data pointers are different widths. On those machines the compiler may not even allow casting between the two classes, but uintptr_t should be able to hold either.

-- Edit --

Was pointed out by @chux, this is not part of the standard and functions are not objects in C. However it usually works and since many people don't even know about these types I usually leave a comment explaining the trickery. Other searches in SO on uintptr_t will provide further explanation. Also we do things in unit testing that we would never do in production because breaking things is good.

sehe
  • 374,641
  • 47
  • 450
  • 633
bd2357
  • 704
  • 9
  • 17
  • Not sure if relevant... Have you tried "opaque typedefs"? Vide: https://www.youtube.com/watch?v=jLdSjh8oqmE – shycha Apr 01 '20 at 00:24
  • @sleske I wish that was available in C. But having stdint.h is better than nothing. (Also wish enums where stronger typed but most debuggers do a good job of figuring them out any way) – bd2357 May 13 '20 at 23:31
  • "but uintptr_t should be able to hold either." --> Not quite. `uintptr_t` good to convert to/from a `void *` and `void *` to/from _object pointers. A function pointer may not round-trip with a `void *`- (e.g. function pointer bigger than `void *`) and by extension, not fit in a `uintptr_t`. – chux - Reinstate Monica Jul 01 '20 at 17:43
  • @chux, Yes, this is not portable in some limited case. Will add a note. It has been many years since I even looked at intel-16bit stuff but segments do make a mess of things. – bd2357 Jul 03 '20 at 18:22