When the integer & # 8596; pointer?

In general folklore it is said that:

  • A type system exists for some reason. Integers and pointers are different types, casting between them is a malpractice in most cases, may indicate a design error and should be avoided.

  • Even when this execution is done, no assumptions are made about the size of integers and pointers (different from void* to int is the easiest way to make x64 code crash), and instead of int , use intptr_t or uintptr_t from stdint.h .

Knowing that when it is really useful to perform such drops?

(Note: having a shorter code for portability costs is not considered "really useful.")




One case that I know:

  • Some blocking multiprocessor algorithms exploit the fact that the 2 + -byte-alligned pointer has some redundancy. Then they use the least significant bits of the pointer as Boolean flags, for example. With a processor having an appropriate set of instructions, this can eliminate the need for a locking mechanism (which would be necessary if the pointer and logical flag were separate). (Note: this practice can even be safely performed in Java through java.util.concurrent.atomic.AtomicMarkableReference)

Anything else?

+76
c ++ c casting pointers
Aug 22 '11 at 11:31
source share
15 answers

I sometimes throw pointers to integers when they somehow have to be part of the hash. In addition, I throw them into integers to execute some bit bits with them under certain implementations, where it is guaranteed that the pointers always leave one or two spare bits, where I can encode the AVL or RB tree information in the left / right pointers instead having to have an extra member. But this is all so implementation specific that I recommend that you never think of it as any common solution. I also heard that sometimes hazard labels can be implemented with such a thing.

In some situations, I need a unique identifier for each object that I pass, for example, servers as a request identifier. Depending on the context, when I need to save some memory, and it's worth it, I use the address of my object as such an identifier and usually should give it to an integer.

When working with embedded systems (for example, in canonical cameras, see chdk) magic additions are often present, therefore, (void*)0xFFBC5235 or the like is also often found there.

change

Just stumbled (in my opinion) over pthread_self() , which returns pthread_t, which is usually a typedef for an unsigned integer. Internally, although it is a pointer to some thread structure representing the thread in question. In general, it can be used elsewhere for an opaque descriptor.

+37
Aug 22 2018-11-11T00:
source share

This can be useful when checking type alignment in general, so that the offset memory comes across with approval, and not just with SIGBUS / SIGSEGV.

eg:.

 #include <xmmintrin.h> #include <assert.h> #include <stdint.h> int main() { void *ptr = malloc(sizeof(__m128)); assert(!((intptr_t)ptr) % __alignof__(__m128)); return 0; } 

(It is clear that in fact I would not play malloc if it was real code, but it illustrates the point)

+15
Aug 22 2018-11-11T00:
source share

Saving a doubly linked list using half space

A XOR Linked List combines the following and previous pointers into a single value of the same size. He does this by matching two pointers together, which requires considering them as integers.

+12
Aug 22 '11 at 16:12
source share

One example is on Windows, for example. the SendMessage() and PostMessage() functions. They take an HWnd (window handle), a message (integral type), and two parameters for the message: WPARAM and LPARAM . Both types of parameters are integral, but sometimes you must pass pointers, depending on the message being sent. Then you will need to overlay a pointer to LPARAM or WPARAM .

I would have avoided it like a plague . If you need to save a pointer, use a pointer type if possible.

+8
Aug 22 '11 at 11:45
source share

The most useful case, in my opinion, is one that actually has the potential to make programs more efficient: several standard and common library interfaces accept one void * argument, which they will pass back to some kind of callback function. Suppose your callback does not require a large amount of data, just one integer argument.

If the callback happens before the function returns, you can simply pass the address of the local (automatic) int variable, and everything will be fine. But the best example for this situation is pthread_create , where the callback is executed in parallel, and you have no guarantee that it will be able to read the argument through a pointer until pthread_create returns. In this situation, you have 3 options:

  • malloc select one int and read the new stream and free .
  • Pass a pointer to the local calling structure containing the int and synchronization object (for example, a semaphore or barrier), and the caller expects it after calling pthread_create .
  • Move int to void * and pass it by value.

Option 3 is much more efficient than any of the other options, both of which are associated with an additional synchronization step (for option 1, synchronization is in malloc / free and will almost certainly be associated with some cost, since the allocation and release of the stream do not coincide).

+8
Aug 22 '11 at 12:40
source share

In embedded systems, access to memory-mapped hardware devices is very common, where the registers have fixed addresses on the memory card. I often model equipment differently in C and C ++ (with C ++ you can use classes and templates), but the general idea can be used for both.

A quick example: suppose you have a timer peripheral in hardware, and it has 2 32-bit registers:

  • a registered free tick counter that decreases at a fixed rate (for example, every microsecond)

  • control register, which allows you to start the timer, stop the timer, enable timer interruption when we reduce the counter to zero, etc.

(Note that real timer peripherals are usually much more complicated).

Each of these registers represents 32-bit values, and the "base address" of the timer periphery is 0xFFFF.0000. You can model the equipment as follows:

 // Treat these HW regs as volatile typedef uint32_t volatile hw_reg; // C friendly, hence the typedef typedef struct { hw_reg TimerCount; hw_reg TimerControl; } TIMER; // Cast the integer 0xFFFF0000 as being the base address of a timer peripheral. #define Timer1 ((TIMER *)0xFFFF0000) // Read the current timer tick value. // eg read the 32-bit value @ 0xFFFF.0000 uint32_t CurrentTicks = Timer1->TimerCount; // Stop / reset the timer. // eg write the value 0 to the 32-bit location @ 0xFFFF.0004 Timer1->TimerControl = 0; 

In this approach, there are 100 options, the pros and cons of which can be discussed forever, but here we only need to illustrate the general use of casting the whole to a pointer. Please note that this code is not portable, it is attached to a specific device, it assumes that the memory area is not disabled, etc.

+5
Aug 22 '11 at 16:52
source share

It is never useful to perform such translations if you do not have complete information about the behavior of your combination of the compiler + platform and you want to use it (your question script is one such example).

The reason I say it is never useful, because in general you do not have control over the compiler and you do not know what optimizations it can solve. Or, to put it another way, you cannot precisely control the machine code that it will generate. So in general, you cannot safely implement this trick.

+3
Aug 22 2018-11-11T00:
source share

The only time I throw a pointer into an integer is when I want to save the pointer, but the only storage I have is an integer.

+2
Aug 22 2018-11-11T00:
source share

When to store pointers in ints correctly? This is correct when you consider it as what it is: using the specifics of the platform or compiler.

The only problem is that you have specific platform / compiler code in your application and you have to transfer your code to another platform because you made assumptions that are no longer fulfilled. By untying this code and hiding it behind an interface that makes no assumptions about the underlying platform, you fix the problem.

As long as you document the implementation, separate it behind a platform-independent interface using descriptors or something that does not depend on how it works behind the scenes, and then forces the code to conditionally compile only on platforms / compilers where it were tested and work, then there is no reason for you not to use any voodoo magic that you encounter. You can even include large chunks of assembly language, native API calls, and kernel system calls, if you want.

However, if your "portable" interface uses integer descriptors, integers the same size as implementation pointers for a particular platform, and this implementation uses pointers inside, why not just use pointers as integer descriptors? In this case, it makes sense to simply convert to an integer, because you have disabled the need for a lookup table for pointers / pointers.

+2
Aug 22 '11 at 11:52
source share

You may need to access memory at a fixed known address, then your address is an integer, and you need to assign it to a pointer. This is quite common in embedded systems. Conversely, you may need to print the memory address and therefore need to translate it into an integer.

Oh, and don’t forget that you need to assign and compare pointers with NULL, which is usually a pointer from 0L

+1
Aug 22 2018-11-11T00:
source share

I have one use for such a thing in the network id of objects. Such an identifier combines the identifiers of a machine (for example, an IP address), a process identifier, and an object address. To send on a socket, the indicative part of such an identifier must be placed in a sufficiently wide integer, so that it transfers the transport back and forth. Part of the pointer is interpreted only as a pointer (= thrown back to the pointer) in the context where it makes sense (the same machine, the same process), on other machines or in other processes that simply serve to distinguish between different objects.

What you need to have is the existence of uintptr_t and uint64_t as an integer type of width. (Well, it only works on machines that have no more than 64 addresses :)

+1
Aug 22 '11 at 12:22
source share

under x64, on can use the top bits of pointers for tags (since only 47 bits are used for the actual pointer). this is great for things like generating runtime code (LuaJIT uses this technique, which is an ancient technique, according to the comments), to perform this tag and tag verification, you will need a listing or union , which are basically the same.

casting pointers to integers can also be very useful in memory management systems that use binning, i.e. it would be easy to find a bit / page for an address through some math, I wrote an example from a blocking distributor some time ago:

 inline Page* GetPage(void* pMemory) { return &pPages[((UINT_PTR)pMemory - (UINT_PTR)pReserve) >> nPageShift]; } 
+1
Aug 22 '11 at 12:33
source share

I used such systems when I try to byte through an array. Often, the pointer will go several bytes at a time, which causes problems that are very difficult to diagnose.

For example, int pointers:

 int* my_pointer; 

moving my_pointer++ will advance 4 bytes (on a standard 32-bit system). However, moving ((int)my_pointer)++ will advance it by one byte.

This is really the only way to accomplish this, with the exception of pointing to (char *). ( (char*)my_pointer)++

Admittedly, (char *) is my usual method as it makes sense.

0
Aug 22 '11 at 18:59
source share

Pointer values ​​can also be a useful source of entropy for seeding a random number generator:

 int* p = new int(); seed(intptr_t(p) ^ *p); delete p; 

The UUID enhancement library uses this trick and several others.

0
Aug 23 '11 at 18:52
source share

There is an old and good tradition to use an object pointer as an impersonal descriptor. For example, some people use it to implement the interaction between two C ++ modules with a flat C-style API. In this case, the type of the descriptor is defined as one of the integer types, and any method must convert the pointer to an integer before it can be transferred to another method that expects an abstract faceless descriptor as one of its parameters. In addition, sometimes there is no other way to break the circular dependence.

0
Aug 24 2018-11-11T00:
source share



All Articles