Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how is conversion to char pointer allowed?

Tags:

We can look at the representation of an object of type T by converting a T* that points at that object into a char*. At least in practice:

int x = 511; unsigned char* cp = (unsigned char*)&x; std::cout << std::hex << std::setfill('0'); for (int i = 0; i < sizeof(int); i++) {   std::cout << std::setw(2) << (int)cp[i] << ' '; } 

This outputs the representation of 511 on my system: ff 01 00 00.

There is (surely) some implementation defined behaviour occurring here. Which of the casts is allowing me to convert an int* to an unsigned char* and which conversions does that cast entail? Am I invoking undefined behaviour as soon as I cast? Can I cast any T* type like this? What can I rely on when doing this?

like image 638
Joseph Mansfield Avatar asked Dec 21 '12 19:12

Joseph Mansfield


People also ask

How does a char pointer work?

You can have pointers to pointers: char **s2 = &s; s2 just stores the address of the variable s . Pointers to pointers come up when you're dealing with arrays of pointers, or when you're passing a pointer to a function and you want the function to be able to write a new pointer value.

What is the advantage of using a char pointer as a string instead of taking an array of characters?

The one advantage that I'm seeing is that with char * it is easier to distinguish "no string provided" and "empty string provided", also it occupies less space then an array. Also, in both cases I can initialize: struct my_struct p { . p = 10, .

Why is a char pointer 4 bytes?

Size of a pointer is fixed for a compiler. All pointer types take same number of bytes for a compiler. That is why we get 4 for both ptri and ptrc.


2 Answers

Which of the casts is allowing me to convert an int* to an unsigned char*?

That C-style cast in this case is the same as reinterpret_cast<unsigned char*>.

Can I cast any T* type like this?

Yes and no. The yes part: You can safely cast any pointer type to a char* or unsigned char* (with the appropriate const and/or volatile qualifiers). The result is implementation-defined, but it is legal.

The no part: The standard explicitly allows char* and unsigned char* as the target type. However, you cannot (for example) safely cast a double* to an int*. Do this and you've crossed the boundary from implementation-defined behavior to undefined behavior. It violates the strict aliasing rule.

like image 139
David Hammen Avatar answered Oct 04 '22 16:10

David Hammen


Your cast maps to:

unsigned char* cp = reinterpret_cast<unsigned char*>(&x); 

The underlying representation of an int is implementation defined, and viewing it as characters allows you to examine that. In your case, it is 32-bit little endian.

There is nothing special here -- this method of examining the internal representation is valid for any data type.

C++03 5.2.10.7: A pointer to an object can be explicitly converted to a pointer to an object of different type. Except that converting an rvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.

This suggests that the cast results in unspecified behavior. But pragmatically speaking, casting from any pointer type to char* will always allow you to examine (and modify) the internal representation of the referenced object.

like image 33
Brent Bradburn Avatar answered Oct 04 '22 16:10

Brent Bradburn