简体   繁体   中英

C++ type casting with pointers

I come from a background of C# and Java and I can't seem to understand what casting with pointers means in C++.

For example:

int x = 1;
char c = *((char*)&x);

What does it do? What it is useful for?

In both your examples you're making mistakes making the code not compile. So I'll assume you're trying to do the following:

int x = 1;
char c = *((char*)&x);

Depending on your architecture, c will now have either the value of the least or the most significant byte of x . In this example this would be either 0 or 1 (this can actually be used to detect the byte ordering).

Your second example won't work, cause you're trying to ignore the const resulting in an illegal operation/bad cast (this is also called "const correctness").

Edit: Regarding your comment about "what does it mean?":

In expressions: &somevariable will return the address of somevariable . *somevariable will assume the contents of somevariable are the address of the actual value, which is then returned.

In declarations: datatype is a normal variable/object. This is passed "by value". datatype& is a reference. This works exactly like normal variables in Java/C# and is passed by reference. datatype* is a pointer. This just contains the address where the actual value is located (see above) and is essentially passed by reference as well.

Actual casts work pretty much similar to Java/C#, but pointers are just that: They point to the location of the actual value. While this might confuse you, pointers in C/C++ work pretty much like the standard variables/references used in Java/C#.

Look at this:

MyClass x; // object of MyClass
MyClass *x; // pointer to an object of MyClass - the actual value is undefined and trying to access it will most likely result in an access violation (due to reading somewhere random).
MyClass *x = 0; // same as above, but now the default value is defined and you're able to detect whether it's been set (accessing it would essentially be a "null reference exception"; but it's actually a null pointer).
MyClass &x = MyClass(); // creating a new reference pointing to an existing object. This would be Java's "MyClass x = new MyClass();"

Casting in C++ works just like casting in Java, no pointers involved.

int x = 1;
char c = (char) x; // Lose precision

However, what you are doing here:

int x = 1;
char *c = (char *)x;

is telling the compiler that the value of x is the address of a character. It is equivalent to

char *c;
c = 1; // Set the address of c to 0x0000000000000001

There are very few times you need to do this.

There are two fundamentally different concepts in C++ which are both sometimes referred to as "casting": One is conversion , and one is reinterpretation .

Conversion creates a new object with the "same value" as an existing object, but of a different type. Here are some examples:

Example 1: type promotion

// 1a: promote int to double to get the correct type of division

int numerator = rand(), denominator = rand();
double d = double(numerator) / double(denominator); 

// 1b: convert int to double to achieve a particular argument deduction

int n;
template <typename T> void do_numeric_stuff(T x) { /* ... */ }

do_numeric_stuff(double(n));

Example 2: Derived-to-base conversion

struct B { }; struct D : B { };
D x;

D * p = &x;  // pointer to x
B * q = p;   // implicit conversion; may change the value!


On the other hand, reinterpretation allows us to treat one variable as though it was another one. About the only correct and useful application for this is serialization , in one form or another.

Example 3: Serialization

std::ofstream file("output.bin");    // output file
char large_buffer[HUGE];             // in-memory buffer

unsigned int n = get_data();

char const * p = reinterpret_cast<char const *>(&n);
file.write(p, p + sizeof n);                         // write the bytes of `n`
std::copy(p, p + sizeof n, large_buffer);            // ditto

std::copy(large_buffer + 17, large_buffer + 17 + sizeof n,
          reinterpret_cast<char *>(&n));   // repopulate `n` from buffer

The standard says that it is undefined behaviour to access an object through a pointer that is not of the correct type (also called "type punning"). While it is OK to store an object pointer in, say, a void* and then convert it back and use it, it is not OK to treat a float as though it was an integer, etc. The only acceptable way of accessing one object as though it was another is the one I demonstrated, namely treating an object of type T as though it was an array char[sizeof(T)] — that is, you are allowed to access the underlying binary representation of every object.

You should avoid c-type casts like (char*) by all means. If you really have to do a type cast have a look at dynamic_cast , static_cast and reinterpret_cast .

But as already stated, you rarely need casting at all.

Have a look here for fruther information: http://www.cplusplus.com/doc/tutorial/typecasting/

http://www.parashift.com/c++-faq/static-typing-and-cpp.html

http://www.parashift.com/c++-faq-lite/print-char-or-ptr-as-number.html

I used many time ago that idiom to access HW at specified address, on custom IO board. So for instance to write at PIC (programmable interrupt controller) to reset some flag (fictious code):

#define PIC_LOC 0x1000
#define PIC_ENABLE_PORT *((char*)(PIC_LOC+0x10))
#define BIT_ENABLE (1 << 3)

...
PIC_ENABLE_PORT |= BIT_ENABLE;
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM