I'm trying to cast a pointer to another type using reinterpret_cast
class MyClassA
{
int x;
int y;
public:
MyClassA();
~MyClassA();
};
class MyClassB
{
int x;
int y;
public:
MyClassB();
~MyClassB();
};
For example, if I cast a pointer to MyClassA to MyClassB, using reinterpret_cast would this conversion work? what about code portability?
And also, as I noted:
(5.2.10/4) A pointer can be explicitly converted to any integral type
large enough to hold it.
Does it mean any pointer e.g MyClassA* can only be converted to int* pointer? if i'm correct?
(5.2.10/4) A pointer can be explicitly converted to any integral type large enough to hold it.
This means int* to int. Pointers aren't integral types.
Casting pointers of unrelated types is bad news and shouldn't be done. It may work, but is not portable.
Inheritance will work though. Have the types inherit from a base class!
As to whether this works or not I do not know, that would be implementation dependant.
However there are no guarantee by the standard that this would work (so don't do it), MyClassA and MyClassB are two separate types that are non compatible even if they are structurally the same.
Same applies to int*.
if you need conversion between then then you can make an A to B assignment operator
class MyClassA{
...
operator=(const MyClassB& mcb)
{
this.x=mcb.x;
this.y=mcb.y;
}
};
And if you need access to an integer element inside of MyClassA.
//in MyClassA
int& getX(){ return x; }
const int& getX() const { return x; }
int& x=mca.getX();
That doesn't mean you can cast unrelated types. It means you can cast a pointer to a 64bit integer (for example) if on your platform 64bit integer is sufficiently big enough to contain a pointer value.
PS: I would like to mention that what you have done is totally deviating from the standard but you might get away with it on many platforms / compilers :)
My answer to the first is yes. A pointer is just a variable (integral) whose value is an address to another memory location. Which is why you are able to do the following.
(*(void(*)())0)(); /*Ref: Andrew Koenig C Traps and Pitfals*/
or
#define CARD_INTERFACE_ADDRESS 0x4801C
struct A * = new (CARD_INTERFACE_ADDRESS) struct A
MyClassA * ptr_a cannot (logically) be converted to int* ptr_i because what you are saying is that the the address held by the variable ptr_a is the address of MyClassA in the former while in the latter you are saying that saying that ptr_i is the address of an int.
Related
X is defined as the following:
struct X
{
Y y;
// more fields...
int a;
};
I have a variable of type X. However, I would like to cast it to the type of its first member, in order to pass that into a function. I know that the C Standard permits it (and I suppose the C++ one does so as well).
In C I would do it like so:
X x;
Y* y = (Y*) x;
doStuff(y);
What type of cast is the right one in C++ for this? static_cast or reinterpret_cast?
None.
You can't mess around with objects using pointers like that. C++ is not C, and these are not "just bytes" (contrary to popular belief).
And you don't need to!
Pass &x.y instead; it's already the Y* you want.
I'd always recommend using static_cast instead of reinterpret_cast in any situation where the static_cast isn't rejected by the compiler. If possible try to avoid doing any casting at all - in this case you probably want: Y* y = &x.y.
To answer the comment:
In this case, I have a PROCESS_MEMORY_COUNTERS_EX
variable. However the WinAPI function GetProcessMemoryInfo takes a
PROCESS_MEMORY_COUNTERS*. The former type starts with the exact same
fields as the latter, and adds a few at the end. The intended usage is
to pass into the function a pointer to the latter type, even if we
hold a pointer to the former (larger) type.
The documentation for GetProcessMemoryInfo() states that the second parameter is:
A pointer to the PROCESS_MEMORY_COUNTERS or PROCESS_MEMORY_COUNTERS_EX
structure that receives information about the memory usage of the
process.
The Win32 API is a C API, and not a C++ one, so you can just use a C style cast here, or preferably a reinterpret_cast to make your intention clearer. I'd expect static_cast to be rejected by the compiler in this case. Note that the third cb parameter is there to tell the function which type of structure you actually provided - it should be set to either sizeof(PROCESS_MEMORY_COUNTERS) or sizeof(PROCESS_MEMORY_COUNTERS_EX).
#FredLarson In this case, I have a PROCESS_MEMORY_COUNTERS_EX variable. However the WinAPI function GetProcessMemoryInfo takes a PROCESS_MEMORY_COUNTERS*. The former type starts with the exact same fields as the latter, and adds a few at the end. The intended usage is to pass into the function a pointer to the latter type, even if we hold a pointer to the former (larger) type.
The cleanest way to accomplish that would be probably (ab)using inheritance. This way, you can have your _EX type share members with the base type while actually being an instance of it.
struct X {
int a;
int b;
};
struct X_EX : public X {
int other_member;
};
void doStuff(X*);
void foo(X_EX* ptr) {
doStuff(ptr);
}
However, do note that "Inherit-to-extend" is seen as a code smell, and something to avoid if possible nowadays. I'd make sure to put a comment explaining why it's necessary here.
Why the following is wrong in C++ (But valid in C)
void*p;
char*s;
p=s;
s=p; //this is wrong ,should do s=(char*)p;
Why do I need the casting,as p now contains address of char pointer and s is also char pointer?
That's valid C, but not C++; they are two different languages, even if they do have many features in common.
In C++, there is no implicit conversion from void* to a typed pointer, so you need a cast. You should prefer a C++ cast, since they restrict which conversions are allowed and so help to prevent mistakes:
s = static_cast<char*>(p);
Better still, you should use polymorphic techniques (such as abstract base classes or templates) to avoid the need to use untyped pointers in the first place; but that's rather beyond the scope of this question.
The value doesn't matter, the type does. Since p is a void pointer and s a char pointer, you have to cast, even if they have the same value. In C it will be ok, void* is the generic pointer, but this is incorrect in C++.
By the way, p doesn't contains char pointer, it's a void pointer and it contains a memory address.
In general, this rule doesn't even have anything to do with pointers. It's just that you can assign values of some type to variables of other types, but not always vice versa. A similar situation would be this:
double d = 0.0;
int i = 0;
d = i; // Totally OK
i = d; // Warning!
So that's just something you have to live with.
Why the following is wrong in C++ (But valid in C)
void*p;
char*s;
p=s;
s=p; //this is wrong ,should do s=(char*)p;
Why do I need the casting,as p now contains address of char pointer and s is also char pointer?
That's valid C, but not C++; they are two different languages, even if they do have many features in common.
In C++, there is no implicit conversion from void* to a typed pointer, so you need a cast. You should prefer a C++ cast, since they restrict which conversions are allowed and so help to prevent mistakes:
s = static_cast<char*>(p);
Better still, you should use polymorphic techniques (such as abstract base classes or templates) to avoid the need to use untyped pointers in the first place; but that's rather beyond the scope of this question.
The value doesn't matter, the type does. Since p is a void pointer and s a char pointer, you have to cast, even if they have the same value. In C it will be ok, void* is the generic pointer, but this is incorrect in C++.
By the way, p doesn't contains char pointer, it's a void pointer and it contains a memory address.
In general, this rule doesn't even have anything to do with pointers. It's just that you can assign values of some type to variables of other types, but not always vice versa. A similar situation would be this:
double d = 0.0;
int i = 0;
d = i; // Totally OK
i = d; // Warning!
So that's just something you have to live with.
I have a const pointer to a pointer to a Fred and I don't understand why a static_cast isn't sufficient.
typedef struct {
int n;
} Fred;
Fred *pFred;
Fred **const ppFred = &pFred;
void **const ppVoid = static_cast<void ** const>(ppFred);
Please could someone explain why a reinterpret_cast is needed to convert a pointer to Fred*to a pointer to void* but static_cast is fine to convert pointer to Fred to a pointer to void.
There's no requirement that a Fred* and a void* have the same size
and representation. (I've worked on machines where they didn't,
although that was before my C++ days.) When you convert Fred* to
void*, you get a new pointer, with a possibly different size and
representation, but there is no information about the size and
representation of the object the void* points to. You know that it is
unknown, and the only way to use this void* is to cast it back to a
Fred* (modulo things like cv-qualifiers). When you convert Fred**
to void**, you're converting from a pointer to a concrete type (a
pointer to a Fred*) to a pointer to another concrete type (a pointer
to a void*). And since there's no guarantee that these two concrete
types have the same size and representation, the conversion requires a
reinterpret_cast. void is a special, non-concrete type, so you can
static_cast a pointer to any type to and from a pointer to void.
void* is just another concrete pointer type, so casting to and from
pointers to it follows the usual rules (and requires a
reinterpret_cast).
In many ways, the situation is very much like int and double, where
void* plays the role of int (say), and Fred* the role of double.
There's no problem static_casting between int and double, but
casts between int* and double* require reinterpret_cast.
All object pointers are convertible to void*, so a static cast is fine for that. However, converting between T* and U* in general requires a reinterpret cast, since arbitrary pointers are not mutually convertible. (And substitute T = Fred*, U = void*.)
static_cast won't work to convert Fred ** to void ** because it's not a sensible conversion : the pointers to Fred* and to void* are not necessarily created the same way (i.e. alignments problems on some platforms). You can be sure that a void* which can point to any byte in memory can point to a Fred object as well, but that's not the case for void** pointers.
Disclaimer
The following is hand-waving for the purpose of making things easily understood, not a technically correct description.
The hand-waving
One possible way to introduce void is:
void is similar (not the same thing as) the Java Object universal superclass.
void can be seen as an abstract base of every class and non-class type. (With this metaphor, void would also be a quasi-virtual base type: conversion to void* is never ambiguous.)
So you can see the implicit conversion from T* to void* as a derived-to-base conversion, and the reverse static_cast is like a base to derived down-cast. When a void* does not really point to a T, you should not do a static_cast<T*> (when a Base* does not really point to a Derived, you should not do a static_cast<Derived*>).
Disclaimer, again
Seriously, void is not an abstract base class, and cannot be formally treated as one in many cases:
You cannot formally describe void either as a virtual base (or static_cast would break) or a non-virtual base (or conversions to void* would be ambiguous when multiple inheritance is used).
There is no void& type. This base class metaphor just does extend beyond pointers.
Please, DO NOT go tell people "void is the universal C++ base class, like Java Object". Do not repeat anything I wrote here without the full disclaimers.
Only in some cases, void behaves like a base class for the purpose of pointer implicit conversions and casts.
You cannot write programs based on metaphors, but on the real C++ rules.
This metaphor might help. Or not. Either way, do not ever try to draw logical conclusions based on a metaphor.
If I have the following struct:
struct Foo { int a; };
Is the code bellow conforming with the C++ Standard? I mean, can't it generate an "Undefined Behavior"?
Foo foo;
int ifoo;
foo = *reinterpret_cast<Foo*>(&ifoo);
void bar(int value);
bar(*reinterpret_cast<int*>(&foo));
auto fptr = static_cast<void(*)(...)>(&bar);
fptr(foo);
9.2/20 in N3290 says
A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.
And your Foo is a standard-layout class.
So your second cast is correct.
I see no guarantee that the first one is correct (and I've used architecture where a char had weaker alignment restriction than a struct containing just a char, on such an architecture, it would be problematic). What the standard guarantee is that if you have a pointer to int which really point to the first element of a struct, you can reinterpret_cast it back to pointer to the struct.
Likewise, I see nothing which would make your third one defined if it was a reinterpret_cast (I'm pretty sure that some ABI use different convention to pass structs and basic types, so it is highly suspicious and I'd need a clear mention in the standard to accept it) and I'm quite sure that nothing allow static_cast between pointers to functions.
As long as you access only the first element of a struct, it's considered to be safe, since there's no padding before the first member of a struct. In fact, this trick is used, for example, in the Objecive-C runtime, where a generic pointer type is defined as:
typedef struct objc_object {
Class isa;
} *id;
and in runtime, real objecs (which are still bare struct pointers) have memory layouts like this:
struct {
Class isa;
int x; // random other data as instance variables
} *CustomObject;
and the runtime accesses the class of an actual object using this method.
Foo is a plain-old-data structure, which means it contains nothing but the data you explicitely store in it. In this case: an int.
Thus the memory layout for an int and Foo are the same.
You can typecast from one to the other without problems. Whether it's a clever idea to use this kind of stuff is a different question.
PS:
This usually works, but not necessarily due to different alignment restrictions. See AProgrammer's answer.