casting structure pointer to union pointer in C++ - c++

I have a Union containing various struct member.
union U {
struct S1 as_s1;
struct S2 as_s2;
…
};
How can I cast pointer to struct as_s1 to a pointer to union U in C++?
I know because of this that it can be easily done using C casting. But I want to use the feature of Advance class type casting of C++ without causing any errors.

From the standard 6.9.2.4.
Two objects a and b are pointer-interconvertible if:
they are the same object, or
one is a standard-layout union object and the other is a non-static data member of that object (12.3),
one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object (12.2), or
there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast (8.2.10).
This means that you can convert them to each other using reinterpret_cast. However, you cannot access the memory of wrong type. E.g., following is a well-defined code:
#include <iostream>
struct S1 {
int i;
};
struct S2 {
short int i;
};
union U {
struct S1 as_s1;
struct S2 as_s2;
};
void printUnion(U* u, int type) {
if (type == 0){
S1 *s1 = reinterpret_cast<S1*>(u);
std::cout << s1->i << std::endl;
} else {
S2 *s2 = reinterpret_cast<S2*>(u);
std::cout << s2->i << std::endl;
}
}
int main() {
S1 s1{1};
printData(reinterpret_cast<U*>(&s1), 0);
S2 s2{2};
printData(reinterpret_cast<U*>(&s2), 1);
}
But, if you give a wrong type parameter to the printData-function, the behavior is undefined.
In c++ it is hard to imagine a program with a good design where the cast would be needed. In c if you already have a need for a union object there might be a case where this could be used to implement polymorphism (of course no reinterpret_cast there). Though it is usually done with void*.

The proper casting for such pointer casts is reinterpret_cast:
#include <stdio.h>
struct S1 {
int x,y;
};
struct S2 {
double a,b;
};
union U {
struct S1 as_s1;
struct S2 as_s2;
};
int main() {
struct S1 mys1;
union U *uptr = reinterpret_cast<union U*>(&mys1);
uptr->as_s1.x = 42;
printf("%d\n",mys1.x);
return 0;
}
Beware that since sizeof(struct S1) < sizeof(struct S2), in this example, and you only allocated enough memory for the size of S1, if you try to do anything on uptr->as_s1.b you will corrupt the stack.

Related

Clang fails to detect uninitialized class members in assignment operator/ copy constructor

Clang doesn't check if all class members have been initialized inside overloaded assignment operators/copy constructors in the contrary to Lint. Instead of that Clang check usage of uninitialized variables. Such approach should be sufficient but what in case of the static casting as it is in following code:
#include <iostream>
using namespace std;
struct B
{
int member;
B()
{
member =111;
}
B(B const & )
{
}
B& operator=(B const & )
{
}
};
struct D : public B
{
void hello() const
{
cout << "member value " << member << "\n";
}
D()
{
}
};
int main()
{
D d;
D d2 = d;
B* br ;
D* another_d = static_cast<D*>(br);
another_d->hello();
}
Static casting is just coping byte by byte and it can't guarantee that all members are initialized however it is a gap for an unsecure code and it can be avoided by checking body of copy consructor as it is done in lint case.
So it could be an input for a Feature Request. What is your opinion?
Here you violate aliasing rules*:
B* br;
D* another_d = static_cast<D*>(br);
Since br doesn't actually point to a D*, you should not cast to one. As a result, this is undefined beavior.
And then here is more undefined behavior:
another_d->hello();
Trying to dereference the pointer another_d at all (even as a B*) is undefined because B* br remains uninitialized.
Anything goes when we're in UB land.
*[expr.static.cast]:
...If the prvalue of
type “pointer to cv1 B” points to a ``B that is actually a subobject of an object of type D, the resulting pointer
points to the enclosing object of type D. Otherwise, the behavior is undefined.

What does it mean to have three elements in typedef in C++?

I know from c++ primer that we can use typedef in the following ways:
typedef int mytype;
typedef int *mytype;
However, the following code also compiles, and it seems to create a new type "rt", I am curious what is the type of rt, and what are common uses of this kind of typedef?
class A{
public:
int c;
};
typedef int A::* rt;
It is not a "three elements typedef", it is a pointer to member variable typedef. You can find more information about pointer to member variable here.
In your precise case, it allows you to instantiate variables of type "rt" that will point to a precise member of type int of A class, and then use it to access this member on A instances.
#include <iostream>
class A{
public:
int c;
};
typedef int A::* rt;
int main() {
A instance;
rt member; // This is a pointer to A member.
member = &A::c; // This pointer will point on c member of A class
instance.c = 0;
instance.*member += 2; // As member point on c, this code access to the c member.
std::cout << instance.c << std::endl; // This will now output "2".
}
It's pointer to member variable.
You define it with this syntax: int A::* pointer;, and initialize it $A::c and read it's value instance.*pointer.
A instance;
int A::* pointer = &A::c;
instance.*pointer = 10;
Actually it's an offset from beginning of the class that allow you to hold a pointer to int that is a member variable of class A.

Get pointer to object from pointer to some member

Suppose there's a structure
struct Thing {
int a;
bool b;
};
and I get a pointer to member b of that structure, say as parameter of some function:
void some_function (bool * ptr) {
Thing * thing = /* ?? */;
}
How do I get a pointer to the containing object? Most importantly: Without violating some rule in the standard, that is I want standard defined behaviour, not undefined nor implementation defined behaviour.
As side note: I know that this circumvents type safety.
If you are sure that the pointer is really pointing to the member b in the structure, like if someone did
Thing t;
some_function(&t.b);
Then you should be able to use the offsetof macro to get a pointer to the structure:
std::size_t offset = offsetof(Thing, b);
Thing* thing = reinterpret_cast<Thing*>(reinterpret_cast<char*>(ptr) - offset);
Note that if the pointer ptr doesn't actually point to the Thing::b member, then the above code will lead to undefined behavior if you use the pointer thing.
void some_function (bool * ptr) {
Thing * thing = (Thing*)(((char*)ptr) - offsetof(Thing,b));
}
I think there is no UB.
X* get_ptr(bool* b){
static typename std::aligned_storage<sizeof(X),alignof(X)>::type buffer;
X* p=static_cast<X*>(static_cast<void*>(&buffer));
ptrdiff_t const offset=static_cast<char*>(static_cast<void*>(&p->b))-static_cast<char*>(static_cast<void*>(&buffer));
return static_cast<X*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(b))-offset));
}
First, we create some static storage that could hold an X. Then we get the address of the X object that could exist in the buffer, and the address of the b element of that object.
Casting back to char*, we can thus get the offset of the bool within the buffer, which we can then use to adjust a pointer to a real bool back to a pointer to the containing X.
My proposal is derived from the #Rod answer in Offset from member pointer without temporary instance, and the similar #0xbadf00d's one in Offset of pointer to member.
I started imagining a form of offset driving the implementation of a pointer to a class data member, later confirmed by the post in question and the tests i've made.
I'm not a C++ practitioner so sorry for the brevity.
#include <iostream>
#include <cstddef>
using namespace std;
struct Thing {
int a;
bool b;
};
template<class T, typename U>
std::ptrdiff_t member_offset(U T::* mem)
{
return
( &reinterpret_cast<const char&>(
reinterpret_cast<const T*>( 1 )->*mem )
- reinterpret_cast<const char*>( 1 ) );
}
template<class T, typename U>
T* get_T_from_data_member_pointer (U * ptr, U T::*pU) {
return reinterpret_cast<T*> (
reinterpret_cast<char*>(ptr)
- member_offset(pU));
}
int main()
{
Thing thing;
thing.b = false;
bool * ptr = &thing.b;
bool Thing::*pb = &Thing::b;
std::cout << "Thing object address accessed from Thing test object lvalue; value is: "
<< &thing << "!\n";
std::cout << "Thing object address derived from pointer to class member; value is: "
<< get_T_from_data_member_pointer(ptr, &Thing::b) << "!\n";
}

What about std::array storage placement?

I want to have mechanism that allows me to concatenate variadic function parameters (all of them are convertable into value of some specific plain-old-data type F) into a raw data storage of appropriate size (size is greater than or equal to sum of parameters sizes). I wrote the following code:
#include <iostream>
#include <iterator>
#include <new>
#include <cstdlib>
#include <cassert>
#include <array>
#include <tuple>
template< typename F >
struct repacker
{
constexpr
repacker(F * const _storage)
: storage_(_storage)
{
static_assert(std::is_pod< F >::value, "Underlying type is not a POD type.");
}
F * const storage_;
template< typename... P >
auto operator () (P && ...params) const
{
constexpr auto N = sizeof...(P);
using A = std::array< F, N >; // using A = F [N]; this eliminates the problem
static_assert(sizeof(A) == sizeof(F) * N, "This compiler does not guarantee, that this code to be working.");
#ifndef _NDEBUG
auto a =
#else
std::ignore =
#endif
new (storage_) A{F(params)...};
assert(static_cast< void * >(a) == static_cast< void * >(a->data()));
return N;
}
};
int main()
{
using F = double;
constexpr auto N = 6;
F * a = new F[N];
{
F x(1.0);
F const y(2.0);
repacker< F > r(a);
auto const M = r(x, y, 3.0, 4, 5.0f, 6.0L);
assert(M == N);
}
std::copy(a, a + N, std::ostream_iterator< F const & >(std::cout, " "));
std::cout << std::endl;
delete [] a;
return EXIT_SUCCESS;
}
But I am not sure that the assert(static_cast< void * >(&a) == static_cast< void * >(a.data())); assertion is true for all the compilers. This is a necessary condition for a code to be working.
Is it always the assertion is true?
This is a necessary condition for a code to be working.
No, it is not. OK, it is necessary, but it is not sufficient. Another necessary condition for this (very terrible) code to be working is:
sizeof(std::array<F, N>) == sizeof(F) * N;
And that is not guaranteed by the standard. std::array is not layout-compatible with C-style arrays. The contents of std::array are, but not the full type itself.
If you want to initialize some object in memory you allocate in blocks of bits, you should new up a char[] array, not an array of F. You should allocate this:
char *a = new char[sizeof(std::array<F, N>)];
#AndyProwl pointed out something very important:
std::array is guaranteed to be an aggregate as defined by C++11 8.5.1/1:
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equalinitializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
Let us test that against C++11 9/7:
A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference
[...]
Violationg this is easier than one might expect:
struct violator { virtual ~violator () { } };
typedef ::std::array<violator, 2> violated;
Here the type violated would have a data member that is of type array of a non-standard-layout class.
Therefore the guarantee expressed in C++11 9.2/20 (that allows reinterpreting a pointer to the class as one to its first member, and is as far as I can see the only passage in the standard that might make your assumption valid) does not hold in all cases for ::std::array.
Standard layout types guarantee that you can convert a pointer to them to a pointer of their first member using reinterpret_cast. IIRC reinterpret_cast can potentially return a different address than used as input (due to alignment restriction).

Explicit type casting of object to int *

What is the output of the following c++ code ?
#include<iostream>
using namespace std;
class IndiaBix
{
int x, y;
public:
IndiaBix(int xx)
{
x = ++xx;
}
~IndiaBix()
{
cout<< x - 1 << " ";
}
void Display()
{
cout<< --x + 1 << " ";
}
};
int main()
{
IndiaBix objBix(5);
objBix.Display();
int *p = (int*) &objBix;
*p = 40;
objBix.Display();
return 0;
}
I did n't understand the following line ::
int *p = (int*) &objBix;//Explicit type cast of a class object to integer pointer type
It is possible to cast an object pointer (of a standard-layout type) to a pointer to its first member. This is because it is guaranteed that the first member of a standard-layout object has the same address as the overall object:
c++11
9.2 Class members [class.mem]
20 - 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.
Thus int *p = (int*) &objBix; is a pointer to objBix.x, since objBix is standard-layout; both its data members x and y are private, and the class has no virtual methods or base classes.