Switching Unknown Pointer Types






Switching Unknown Pointer Types

Problem

You need a generic method that accepts two pointers and switches the addresses that each pointer points to. In other words, if x points to an integer variable Foo and y points to an integer variable Bar, you want to switch x so that it points to Bar and switch y so that it points to Foo.

Solution

Create a method that accepts two void pointers. The following method accepts two pointers to void by reference. The by reference is required since you are actually switching the values contained in the pointer variables, not the value that the pointer is pointing to:

	public unsafe void Switch(ref void* x, ref void* y)
	{
	    void* temp = x;
	    x = y;
	    y = temp;
	}

The following test code calls the Switch method with two integer variables that point to different memory locations:

	public unsafe void TestSwitch( )
	{
	    int x = 100;
	    int y = 20;
	    int* ptrx = &x;
	    int* ptry = &y;

	    Console.WriteLine(*ptrx + "\t" + (int)ptrx);
	    Console.WriteLine(*ptry + "\t" + (int)ptry);

	    // Convert int* to void*.
	    void* voidx = (void*)ptrx;
	    void* voidy = (void*)ptry;

	    // Switch pointer values.
	    Switch(ref voidx, ref voidy);

	    // Convert returned void* to a usable int*.
	    ptrx = (int*)voidx;
	    ptry = (int*)voidy;

	    Console.WriteLine(*ptrx + "\t" + (int)ptrx);
	    Console.WriteLine(*ptry + "\t" + (int)ptry);
	}

The following is displayed (note that the addresses will be different on different machines):

	100     1243108
	20      1243104
	20      1243104
	100     1243108

The TestSwitch method could have been written just as easily with another data type, such as a byte, shown here:

	public unsafe void TestSwitch( )
	{
	    byte x = 100;
	    byte y = 20;
	    byte* ptrx = &x;
	    byte* ptry = &y;

	    Console.WriteLine(*ptrx + "\t" + (int)ptrx);
	    Console.WriteLine(*ptry + "\t" + (int)ptry);

	    // Convert byte* to void*.
	    void* voidx = (void*)ptrx;
	    void* voidy = (void*)ptry;

	    // Switch pointer values.
	    Switch(ref voidx, ref voidy);
	    // Convert returned void* to a usable byte*.
	    ptrx = (byte*)voidx;
	    ptry = (byte*)voidy;

	    Console.WriteLine(*ptrx + "\t" + (int)ptrx);
	    Console.WriteLine(*ptry + "\t" + (int)ptry);
	}

All that had to be done is to change the int* types to byte* types. The problem here is that there are no safeguards against passing in pointers to different types. This can be a big problem, if you swap out, say, a byte and an integer.

Discussion

A void pointer has no type and therefore cannot be dereferenced, nor can pointer arithmetic be applied to this type of pointer. A void pointer does have one very useful function, though; it can be cast to a pointer of any other type. Notice that the Switch method, used in the Solution for this recipe, takes two parameters of type void* by reference. You are declaring that any pointer type may be passed to these two parameters. Once inside the Switch method, you can manipulate the value contained in the void pointers. However, since you do not know the original type that the void* was cast from, you cannot dereference the void*.

The one drawback to this technique is that before the Switch method is called in the TestSwitch method, the int* or byte* pointers must be cast to a void*. When the Switch method returns, the void* pointers must be cast back to their original types before they can be used. The reason for this casting is that you are passing the void* pointers by reference instead of by value.

You could pass the void* pointers by value instead and simply Switch the values pointed to, rather than the memory locations pointed to, in the Switch method. This new SwitchValues method would look something like this:

	public unsafe void SwitchValues(void* x, void* y)
	{
	    void* temp = x;
	    *x = *y;
	    *y = *temp;
	}

Unfortunately, this code will not compile, since you cannot dereference a void*. The void* must be cast to its original type before it can be dereferenced. To do this, you must also pass along the type information to the SwitchValues method. This can become very cumbersome, and it reduces the generic character of this method as well.

See Also

See the section "A.4 Pointer Conversions" in the C# specification.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows