3

I want to cast a pointer pc which points to char to a point pi which points to int

char *pc; int *pi; pi = (int*)pc // compiler complaint about old-style cast pi = static_cast<int *>(static_cast<void *>(pc)) // no complaint any more but too complex 

is there any simpler ways to do this cast and make compiler silence?

6
  • 1
    First of all, why are you trying to do this? It's complicated/a warning because it's code smell. Secondly, why are you unhappy with the second version? It works, doesn't it? Commented Dec 28, 2017 at 9:52
  • 1
    (int*)pc is short, but it hides a hefty conversion. Your compiler is most probably warning you so you aren't caught off guard. When you spell the conversions explicitly, it just assumes you know what you are doing. Commented Dec 28, 2017 at 9:54
  • 4
    What are you actually trying to do? Because accessing such a pointer is (usually) undefined behavior. You usually have to construe a way to always cast the int* to a char* not the other way round. Commented Dec 28, 2017 at 10:02
  • 2
    The answer: don't. The less good answer: search. This has been discussed countless times, in particular how a reinterpret_cast of pointer types is the same as static_cast via void*, and how you can't often do anything useful with the resulting pointer anyway. Sure, there are a specific subset of legitimate cases for it, but there's no evidence from your toy example that you have such a case. And without an explanation of what you're trying to do, not just how you're currently trying to do it, such questions might be doomed to quibbling about the how instead of solving the what :P Commented Dec 28, 2017 at 10:32
  • @underscore_d: Good advice indeed. Me, StoryTeller, M.M and n.m, are still debating the legality. And the final 3 on that list are no charlatans. Commented Dec 28, 2017 at 10:34

3 Answers 3

7

If you really need to do this then reinterpret_cast is your friend:

char *pc = 0; int *pi = 0; pi = reinterpret_cast<int*>(pc); 
Sign up to request clarification or add additional context in comments.

2 Comments

First 7 words being the most important.
@Sean - I agree with Rotem's comment. You really need to highlight the first seven words. There are VERY few real-world circumstances where reinterpret_cast is a preferred solution, due to likelihood of subsequent instances of undefined behaviour.
7

The behaviour on converting, in general, a char* pointer to an int* pointer is undefined. Dereferencing such a pointer will cause you further trouble as you will be breaking strict aliasing rules. Note that the C++ Standard does not require sizeof(char*) to be the same as sizeof(int*).

(Note that converting an unsigned char* pointer to an int* is well-defined if the unsigned char* pointer actually points to an int).

Don't do it. Ever.

20 Comments

@Bathsheba - Accessing the memory is one thing (and I would prefer unsigned char to be on the safe side). But just obtaining a pointer and casting back seems legit.
Pointer casting never violates the strict aliasing rule. The rule is about accessing an object of one type via lvalue of a different type.
It's not undefined to do the cast either. At worst, result is unspecified if the alignment is not correct.
&s + 2 is UB for forming a pointer outside of bounds of any object. But if the source pointer points to an object, then the result of casting it still points to the same storage (or unspecified if misaligned)
The pointer sizes must be such that the behaviour required by the standard can be implemented. The standard explicitly allows converting between pointers to different object types.
|
3
+200

I want to put the back and forth under @Bathsheba's post to rest. So here's an answer about the finer details of what you are doing.


@Sean already suggested you reinterpret_cast your pointers instead. And that is equivalent to your second chain of casts. It says as much in [expr.reinterpret.cast]/7:

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_­cast<cv T*>(static_­cast<cv void*>(v)). [ Note: Converting a prvalue 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.  — end note ]

Now, let's examine each step of the two step conversion. First we have a static_cast<void*>. According to [conv.ptr]/2 (emphasis mine):

A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The pointer value is unchanged by this conversion.

The first conversion doesn't do any alteration to the address. And then it also says in [basic.compound]/5:

A pointer to cv-qualified or cv-unqualified void can be used to point to objects of unknown type. Such a pointer shall be able to hold any object pointer. An object of type cv void* shall have the same representation and alignment requirements as cv char*.

So a char* may store any address a void* may store. Now it doesn't mean the conversion from void* to char* is value preserving, only that they can represent the same values. Now, assuming a very restricted use case, that is enough of a guarantee. But there's more at [expr.static.cast]/13:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion.

Where am I going with this? Assuming pc already holds the address of an int (suitably converted according to the above), then casting the char* to an int* via reinterpret_cast will give you the address of the original int. The note under the first paragraph says as much, and the further quotes prove it. If it doesn't hold the address of an int, you are playing roulette and are likely going to lose. Your program has undefined behavior. You should follow Bathsheba's advice to the letter.

1 Comment

thanks for your explanation,I’m a new programmer and find the compiler complaining about the old-style cast in a old project.I thought it might be a better way to do this and I came here...I did have much to learn.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.