Are pointers to members of an anonymous union equal? - c++

C++11 allows an anonymous union to be defined in a function, and its members can be accessed as variables of the function. If I examine the pointers to the different members, they are the same, but the == operator says they're unequal.
Such strange behavior is typically the result of undefined behavior, but I don't see anything undefined in my code (I made sure to that both members are of the same type).
The behavior is different if I use a named variable of an unnamed union type. In this case, the pointers compare equal.
This program demonstrates both cases:
#include <iostream>
using namespace std;
#ifdef NAMED
// Create a named object of a union type
#define NAME n
#define ADDR(mem) &(NAME.mem)
#else
// Create an anonymous union in main()
#define NAME
#define ADDR(mem) &mem
#endif
int main()
{
union {
int a;
int b;
} NAME;
cout << "&a = " << ADDR(a) << endl;
cout << "&b = " << ADDR(b) << endl;
cout << "(&a==&b) = " << (ADDR(a) == ADDR(b)) << endl;
return 0;
}
When compiled with -DNAMED it prints to identical pointers, and 1 (equal pointers). Without -DNAMED, it again prints identical pointers, but then 0 (unequal pointers).
Tested with g++ 5.4.0, Ubuntu 16.04, x86_64.

Your address checking is well defined (as YSC pointed out) and the standard guarantees that all members shall have the same address (cfr. [class.union]/3).
You must have stumbled upon a now fixed compiler bug.

Related

Type modifiers alternative syntax [duplicate]

What is the difference between
(type)value
and
type(value)
in C++?
There is no difference; per the standard (§5.2.3):
A simple-type-specifier (7.1.5) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4).
Since the question specified the difference between type(value) and (type)value, there is absolutely no difference.
If and only if you're dealing with a comma-separated list of values can there be a difference. In this case:
If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as an rvalue.
As Troubadour pointed out, there are a certain names of types for which the type(value) version simply won't compile. For example:
char *a = (char *)string;
will compile, but:
char *a = char *(string);
will not. The same type with a different name (e.g., created with a typedef) can work though:
typedef char *char_ptr;
char *a = char_ptr(string);
There is no difference; the C++ standard (1998 and 2003 editions) is clear about this point. Try the following program, make sure you use a compiler that's compliant, such as the free preview at http://comeaucomputing.com/tryitout/.
#include <cstdlib>
#include <string>
int main() {
int('A'); (int) 'A'; // obvious
(std::string) "abc"; // not so obvious
unsigned(a_var) = 3; // see note below
(long const&) a_var; // const or refs, which T(v) can't do
return EXIT_SUCCESS;
}
Note: unsigned(a_var) is different, but does show one way those exact tokens can mean something else. It is declaring a variable named a_var of type unsigned, and isn't a cast at all. (If you're familiar with pointers to functions or arrays, consider how you have to use a parens around p in a type like void (*pf)() or int (*pa)[42].)
(Warnings are produced since these statements don't use the value and in a real program that'd almost certainly be an error, but everything still works. I just didn't have the heart to change it after making everything line up.)
There is no difference when both are casts, but sometimes 'type(value)' is not a cast.
Here's an example from standard draft N3242, section 8.2.1:
struct S
{
S(int);
};
void foo(double a)
{
S w( int(a) ); // function declaration
S y( (int)a ); // object declaration
}
In this case 'int(a)' is not a cast because 'a' is not a value, it is a parameter name surrounded by redundant parentheses. The document states
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 can also occur in the context
of a declaration. In that context, the choice is between a function
declaration with a redundant set of parentheses around a parameter
name and an object declaration with a function-style cast as the
initializer. Just as for the ambiguities mentioned in 6.8, the
resolution is to consider any construct that could possibly be a
declaration a declaration.
In c there is no type (value), while in c/c++ both type (value) and (type) value are allowed.
To illustrate your options in C++ (only one has a safety check)
#include<boost/numeric/conversion/cast.hpp>
using std::cout;
using std::endl;
int main(){
float smallf = 100.1;
cout << (int)smallf << endl; // outputs 100 // c cast
cout << int(smallf) << endl; // outputs 100 // c++ constructor = c cast
cout << static_cast<int>(smallf) << endl; // outputs 100
// cout << static_cast<int&>(smallf) << endl; // not allowed
cout << reinterpret_cast<int&>(smallf) << endl; // outputs 1120416563
cout << boost::numeric_cast<int>(smallf) << endl; // outputs 100
float bigf = 1.23e12;
cout << (int)bigf << endl; // outputs -2147483648
cout << int(bigf) << endl; // outputs -2147483648
cout << static_cast<int>(bigf) << endl; // outputs -2147483648
// cout << static_cast<int&>(bigf) << endl; // not allowed
cout << reinterpret_cast<int&>(bigf) << endl; // outputs 1401893083
cout << boost::numeric_cast<int>(bigf) << endl; // throws bad numeric conversion
}

unexpected address for a referenced indirected pointer in a struct as opposed to same declaration with a plain variable?

I have a struct containing a byte array and several typecast references to various points in the array. Bytes 4:7 may be interpreted as a float, int32_t, or uint32_t as determined by other fields in the packet being received over a serial connection. To make access simple (e.g. message.argument.F for a float interpretation), I made multiple references to indirected typecast pointers. But when I ran the program, I got a segfault trying to write to the references in the struct. As near as I can tell, the problem has to do with the container, as illustrated by this example snippet (cpp shell: http://cpp.sh/3vmoy):
#include <iostream>
#include <cstring>
using namespace std;
#define PACKET_SIZE 9
#define ARG_I 4
struct Message{
uint8_t bytes[PACKET_SIZE];
uint8_t* argbytes = static_cast<uint8_t*>(argp);
float& argf = *static_cast<float*>(argp);
void* argp = &bytes[ARG_I];
} message;
int main(){
// USING STRUCT
cout << "Using message struct" << endl;
cout << message.argp << endl; // the pointer at index stored in struct
cout << static_cast<float*>(message.argp) << endl; // casting the pointer to a float* - should be the same
cout << &message.argf << endl; // the address of the float reference cast from argp, ** should be the same BUT IS NOT **
// RAW VARS
uint8_t bytes[PACKET_SIZE];
void* argp = &bytes[ARG_I];
float& argf = *static_cast<float*>(argp);
cout << endl << "using raw vars" << endl;
cout << argp << endl; // a pointer to a byte in an array of bytes.
cout << static_cast<float*>(argp) << endl; // the same pointer cast as a float*
cout << &argf << endl; // the address of a float reference cast from argp, **should be the same AND IS.**
}
I expect to see the same address for the pointer, a typecast pointer, and the address of the reference for the indirected pointer. I do see that if I create an array and the pointer/reference as standalone variables, but not for the same declarations in a struct. What arcane knowledge do I lack to explain this behavior (or what silly thing have I overlooked?)
My thoughts for fixing this are to a) ignore it and just typecast the pointer as necessary instead, or b) make some setter/getter functions to access the argument portion of the serial "packet".
There are two major, fundamental differences between the two alternative chunks of code.
void* argp = &bytes[ARG_I];
float& argf = *static_cast<float*>(argp);
Here, this constructs and initializes argp first, then argf.
float& argf = *static_cast<float*>(argp);
void* argp = &bytes[ARG_I];
And here, it does not.
This initializes argf first, then argp. The consequences of this should be quite apparent.
Note: I'm ignoring all the aliasing rule violations here, that are likely to be a source of further undefined behavior.

C++ Union, garbage value [duplicate]

This question already has answers here:
Accessing inactive union member and undefined behavior?
(5 answers)
Closed 2 years ago.
For the following code
#include <iostream>
using namespace std;
union type
{
int a;
char b ;
};
int main()
{
type first;
first.b = 'a';
cout << first.a << " " << first.b << endl;
}
the output is -858993567 a (MSVC) or 4201057 a(g++ MINGW).
but for
#include <iostream>
using namespace std;
union type
{
int a;
char b ;
};
int main()
{
type first;
first.a = 0;
first.b = 'a';
cout << first.a << " " << first.b << endl;
}
the output is 97 a
And these values are fixed under every circumstances (tried rebooting and creating new workspace/file, hence not garbage values).
So, why did the initialization (in the second case) made a difference?
I have tried it both on visual studio (using MSVC) and visual studio code (using g++).
Update 1
I checked on online IDE which probably use Linux g++, and they give the exact expected answer i.e., 97 a, in both the cases.
If you specify first.a in first code sample - you will get fixed, stable value.
You have union with 4 bytes size and initialize only one byte of them.
Union is like type who can holds any type but this types musts be writed in definition of union, like this:
union Example {
char a;
std::int32_t b;
};
Example ex; /// Create object of union
ex.a = 'c'; /// At this moment a member is valid and b is invalid
std::cout << ex.b; /// This cause undefined behavior
Be aware, size of union object is size of type who need most bytes. In this case size is same as size of b property.

Is there any way to change the type of the variable before initialization can you explain with an example?

int element;
(float)element;
cout << typeid(element).name() << endl;
Concerning:
int element;
(float)element;
cout << typeid(element).name() << endl;
int element; tells the compiler to allocated storage with sizeof (int) (and associated it with symbol element).
Additionally, it remembers the type (at compile time) for further usages of the variable (as expression).
(float)element; tells the compiler to access variable element (it's of type int) and convert its value to float (without further processing). This is a conversion of the temporary value read from element not elements storage or type. – element is still of type int.
To answer (part of) the question
Is there any way to change the type of the variable
No. It's not allowed to change the type of the variable this way.
Concerning the XY problem (suspected by molbdnilo):
It is possible to provide storage for a variable "on demand" (at runtime) using dynamic allocation with new. Though, using new directly is actually discouraged. Allocating something with new should also delete it later when memory is not needed anymore. Handling the delete correctly (double deleteing something is prohibited but not deleteing something causes a memory-leak), is not that easy to maintain.
Please, note that local variables (if not declared static or extern) have a life-time which starts not before scope is entered and ends when scope is left. Hence, it's questionable whether shared storage for alternative types is worth at all. Instead, just the respective number of alternative local variables could be used.
However, it is possible to provide a variable with possible alternative types (where only one is used at at time) with a union or a std::variant (since C++17).
A sample for std::variant:
#include <cassert>
#include <iostream>
#include <variant>
typedef std::variant<int, float> IntOrFloat;
void print(IntOrFloat value)
{
std::cout << "value: ";
if (std::holds_alternative<int>(value)) {
std::cout << std::get<int>(value) << " (int)\n";
} else if (std::holds_alternative<float>(value)) {
std::cout << std::get<float>(value) << " (float)\n";
}
}
int main()
{
IntOrFloat value = 123; // now it's an int
print(value);
value = 1.23f; // now it's a float
print(value);
return 0;
}
Output:
value: 123 (int)
value: 1.23 (float)
Live Demo on coliru

Offsetof Function with std::vector

Could someone explain to me why the offsetof function does not work on std::vectors as shown below:
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
struct FooStruct {
double x;
double y[10];
std::vector<double> z;
};
int main() {
cout << offsetof(FooStruct, x) << endl;
cout << offsetof(FooStruct, y[2]) << endl;
cout << offsetof(FooStruct, z[2]) << endl;
system("Pause");
}
Calling offsetof(FooStruct, z[2]) produces the following compiling error:
cannot apply 'offsetof' when 'operator[]' is overloaded
offsetof(FooStruct, z[2]) makes no sense. The elements of z are not contained within a FooStruct, they're accessed via the std::vector, which has at its core a pointer to some other allocation on the heap within which z[2] can be found.
In any case, the error (which seems confusing I understand) is probably popping up because std::vector overloads operator[], not because your class FooStruct overloads operator[] (which, assuming we see the whole definition, it doesn't).
If you want to find the offset of z[2] in relation to z[0], you could just compute the difference between &z[0] and &z[2] like this: std::cout << (&z[2] - &z[0]) << '\n';
Because offsetof isn't a function but a macro, and only works on POD types, or standard layout class in C++11. It's only there for backward compatibility with C.
The reason the compiler refuses to allow you to use the subscription operator, all issues aside, is because the macro is evaluated at compile time, but the overloaded operator might do some work at runtime to calculate the result.