Bit Field Struct to int in C++ - c++

I have a struct with same type members in it. I am trying to convert it into uint8_t type. I am able to do that but cannot see the output please tell me where I am going wrong. Also I know there are another ways to do it? I am trying to do it this way because I want to get use to static_cast and reinterpret_cast.
Code is below:
int main()
{
struct xs{
bool x :1 ;
bool y :1;
bool z :1;
uint8_t num :5;
} zs;
uint8_t* P = static_cast<uint8_t*>(static_cast<void*>(&zs));
cout << *P << endl;
return 0;
}

There a lot of problems here:
You seem to believe that x, y, and z will all pack into the single uint_8. This is not the case. "Adjacently declared bit fields of the same type can then be packed by the compiler into a reduced number of words"[1]
"The value of sizeof(bool) is implementation defined and might differ from 1"[2] Therefore your xs will be implementation defined, but certainly not equivilent to sizeof(uint_8)
Because xs is not "similar" to a uint_8 according to the rules defined for C++'s type aliasing the behavior of your reinterpret_cast<uint_8*> is undefined
Finally as has been pointed out by many others the reason that you can't see anything is that whatever implementation defined value is at *P it is likely a control character with no visible representation when treated by cout as a char
A possible workaround to the code you have would be to use these definitions:
constexpr uint8_t X = 0B1000'0000;
constexpr uint8_t Y = 0B0100'0000;
constexpr uint8_t Z = 0B0010'0000;
constexpr uint8_t NUM = 0B0001'1111;
uint8_t zs;
Then given that some value is assigned to zs you can perform these functions to output the former bit fields:
cout << ((zs & X) != 0) << endl;
cout << ((zs & Y) != 0) << endl;
cout << ((zs & Z) != 0) << endl;
cout << (zs & NUM) << endl;
Live Example

it is undefined behavior to access an object through a pointer to a type other than the type of the object. it works with most compilers, but technically your programm is allowed to do whatever it wants.
assuming we are not running into a problem mentioned in 1, my guess is that uint8_t is an alias for char, so cout will put a char onto your console.
you did not initialize the memory you are inspecting, so it can be 0. a char with value zero wont print out anything "observeable" in your console, look at the ascii table. try filling your struct with a 50 for example

There are two things that need to be solved here. First off, as some pointed out, you cannot access your object this way. If you want to construct a uint8_t properly, you would need to read the variables inside your struct and do some bit shifts, something like this:
uint8_t value = 0;
value |= (zs.x ? 1 << 7 : 0);
value |= (zs.y ? 1 << 6 : 0);
value |= (zs.z ? 1 << 5 : 0);
value |= zs.num;
Now, the second problem you are facing is that you're trying to output a number of 8-bits wide. By default, this is interpreted as a 'character' and will display as such. In order to accomplish what you want to do, you can either use a variable with a different length (uint16_t, uint32_t, ...) or use std::to_string.
cout << std::to_string(value) << endl;

Related

Regarding Bit Fields in Structure and Union

When using bit fields inside structures like:
struct abc{
int a:3;
unsigned int b:1;
} t;
So, my question is, do variables (with set bit-fields) share the same memory space even inside structures? Because when I saw their representation it looked like - first, a will have 3 bits(from LSB) then 1 bit for b (MSB) and all in one 4-byte(32 bits) memory space.
In case of Unions:
typedef union abc {
unsigned int a:32;
int f:1;
} t;
int main()
{ t q;
q.a = (unsigned int)(pow(2,32)-1);
q.f = 1;
cout << sizeof(t) << endl;
cout << q.a << " " << q.f << endl;
return 0;
}
First of all, the sizeof() operator returns 4 bytes as the maximum size for this union
and as 32 bits are set for variable 1 then how can it even manage space for variable b?
Thank you for reading till the end, I'll really appreciate your answers.

Usual arithmetic conversions and Integer promotion

I'm trying to understand what's going on under the hood of c conversions, and different types promotions and comparing stuff and all of this.
union myUnion{
int intVal;
float floatVal;};
if (m.floatVal == m.intVal)
{
cout << "BINGO!";
}
if (*ptrInt == *ptrInt2)
{
cout << "BINGO!" << endl << *ptrInt << endl << *ptrInt2;
}
The first if statement is evaluated to false and the second if statement to true.
How c compiler interprets this values m.floatVal, m.intVal. I'm mean what's going on down there, into assembly, because that's going to be run on the CPU.
Moreover m.floatVal, m.intVal gets evaluated different values depending on which variable I initialised first.
m.floatVal = 3; first gets something
m.intVal = 3; first gets something else.
In the end there is the same value there!?!?!?!?!?!?
Second example:
char minstogo = 0x98;
if (minstogo <= 7) {
cout << "BEAST!";
} beast is printed
char minstogo = 0x98;
if ((unsigned char)minstogo <= 7) {
cout << "BEAST!";
} nothing is printed
char minstogo = 0x98;
if (minstogo <= (unsigned char)7) {
cout << "BEAST!";
} beast is printed
How the compiler interprets this mess and what is going on down the assembly?
Third example:
How is a float converted to an int? Who the bits are all remapped?
Thank you so much guys! Thank you.
First example:
union myUnion{
int intVal;
float floatVal;};
if (m.floatVal == m.intVal)
{
cout << "BINGO!";
}
This is undefined behaviour in c++. Having written to intVal, reading floatVal is undefined behaviour. Having written to floatVal, reading intVal is undefined behaviour.

Is it more portable to use ~0 or -1 to represent a type with all bits flipped to 1?

I saw an code example today which used the following form to check against -1 for an unsigned 64-bit integer:
if (a == (uint64_t)~0)
Is there any use case where you would WANT to compare against ~0 instead of something like std::numeric_limits<uint64_t>::max() or straight up -1? The original intent was unclear to me as I'd not seen a comparison like this before.
To clarify, the comparison is checking for an error condition where the unsigned integer type will have all of its bits set to 1.
UPDATE
According to https://stackoverflow.com/a/809341/1762276, -1 does not always represent all bits flipped to 1 but ~0 does. Is this correct?
I recommend you to do it exactly as you have shown, since it is the
most straight forward one. Initialize to -1 which will work always,
independent of the actual sign representation, while ~ will sometimes
have surprising behavior because you will have to have the right
operand type. Only then you will get the most high value of an
unsigned type.
I believe this error case is handled so long as ~0 is always case to the correct type (as indicated). So this would suggest that (uint64_t)~0 is indeed a more accurate and portal representation of an unsigned type with all bits flipped?
All of the following seem to be true (GCC x86_x64):
#include <iostream>
#include <limits>
using namespace std;
int main() {
uint64_t a = 0xFFFFFFFFFFFFFFFF;
cout << (int)(a == -1) << endl;
cout << (int)(a == ~0) << endl;
cout << (int)(a == (uint64_t)-1) << endl;
cout << (int)(a == (uint64_t)~0) << endl;
cout << (int)(a == static_cast<uint64_t>(-1)) << endl;
cout << (int)(a == static_cast<uint64_t>(~0)) << endl;
cout << (int)(a == std::numeric_limits<uint64_t>::max()) << endl;
return 0;
}
Result:
1
1
1
1
1
1
1
In general you should be casting before applying the operator, because casting to a wider unsigned type may or may not cause sign extension depending on whether the source type is signed.
If you want a value of primitive type T with all bits set, the most portable approach is ~T(0). It should work on any number-like classes as well.
As Mr. Bingley said, the types from stdint.h are guaranteed to be two's-complement, so that -T(1) will also give a value with all bits set.
The source you reference has the right thought but misses some of the details, for example neither of (T)~0u nor (T)-1u will be the same as ~T(0u) and -T(1u). (To be fair, litb wasn't talking about widening in that answer you linked)
Note that if there are no variables, just an unsuffixed literal 0 or -1, then the source type is guaranteed to be signed and none of the above concerns apply. But why write different code when dealing with literals, when the universally correct code is no more complex?
std::numeric_limits<uint64_t>::max() is same as (uint64_t)~0 witch is same as (uint64_t)-1
look to this example of code:
#include <iostream>
#include <stdint.h>
using namespace std;
int main()
{
bool x = false;
cout << x << endl;
x = std::numeric_limits<uint64_t>::max() == (uint64_t)~0;
cout << x << endl;
x = false;
cout << x << endl;
x = std::numeric_limits<uint64_t>::max() == (uint64_t)-1;
cout << x;
}
Result:
0
1
0
1
so it's more simple to write (uint64_t)~0 or (uint64_t)-1 than std::numeric_limits<uint64_t>::max() in the code.
The fixed-width integer types like uint64_t are guaranteed to be represented in two's complement, so for those -1 and ~0 are equivalent. For the normal integer types (like int or long) this is not necessarily the case, since the C++ standard does not specify their bit representations.

Why does int8_t and user input via cin shows strange result [duplicate]

This question already has answers here:
uint8_t can't be printed with cout
(8 answers)
Closed 8 years ago.
A tiny piece of code drives me crazy but hopefully you can prevent me from jumping out of the window. Look here:
#include <iostream>
#include <cstdint>
int main()
{
int8_t i = 65;
int8_t j;
std::cout << "i = " << i << std::endl; // the 'A' is ok, same as uchar
std::cout << "Now type in a value for j (use 65 again): " << std::endl;
std::cin >> j;
std::cout << "j = " << j << std::endl;
if (i != j)
std::cout << "What is going on here?????" << std::endl;
else
std::cout << "Everything ok." << std::endl;
return 0;
}
If I use int instead of int8_t everything ok. I need this as 8-bit unsigned integers, not bigger. And btw. with unsigned char it's the same behaviour - of course - as with int8_t.
Anyone with a hint?
int8_t is a typedef for an integer type with the required characteristics: pure 2's-complement representation, no padding bits, size of exactly 8 bits.
For most (perhaps all) compilers, that means it's going to be a typedef for signed char.(Because of a quirk in the definition of the term signed integer type, it cannot be a typedef for plain char, even if char happens to be signed).
The >> operator treats character types specially. Reading a character reads a single input character, not sequence of characters representing some integer value in decimal. So if the next input character is '0', the value read will be the character value '0', which is probably 48.
Since a typedef creates an alias for an existing type, not a new distinct type, there's no way for the >> operator to know that you want to treat int8_t as an integer type rather than as a character type.
The problem is that in most implementations there is no 8-bit integer type that's not a character type.
The only workaround is to read into an int variable and then convert to int8_t (with range checks if you need them).
Incidentally, int8_t is a signed type; the corresponding unsigned type is uint8_t, which has a range of 0..255.
(One more consideration: if CHAR_BIT > 8, which is permitted by the standard, then neither int8_t nor uint8_t will be defined at all.)
int8_t and uint8_t are almost certainly character types (Are int8_t and uint8_t intended to behave like a character?) so std::cin >> j will read a single character from stdin and interpret it as a character, not as a number.
int8_t is likely the same as char, which means cin >> j will simply read a single character ('6') from input and store it in j.
int8_t is defined as a typedef name for signed char. So operator >> used with an object of type int8_t behaves the same way as it would be used for an object of type signed char
The _t types aren't first class types, they are typedef aliases the observe certain constraints, e.g. int8_t is a type that can store a signed, 8-bit value.
On most systems, this will mean they are typedefd to char. And because they are a typedef and not a first-class type, you are invoking cin.operator<<(char) and cin.operator>>(char).
When you input "65", cin.operator>>(char) consumes the '6' and places it's ascii value, 54, into variable j.
To work around this you'll need to use a different type, possibly the easiest method being just to use a larger integer type and apply constraints and then cast down:
int8_t fetchInt8(const char* prompt) {
int in = 0;
for ( ; ; ) { // endless loop.
std::cout << prompt << ": ";
std::cin >> in;
if (in >= std::numeric_limits<int8_t>::min()
&& in <= std::numeric_limits<int8_t>::max()) {
std::cout << "You entered: " << in << '\n';
// exit the loop
break;
}
std::cerr << "Error: Invalid number for an int8\n";
}
return static_cast<int8_t>(in);
}
Note that int8_t is signed, which means it stores -128 thru +127. If you want only positive values, use the uint8_t type.

Why is std::cout not printing the correct value for my int8_t number?

I have something like:
int8_t value;
value = -27;
std::cout << value << std::endl;
When I run my program I get a wrong random value of <E5> outputted to the screen, but when I run the program in gdb and use p value it prints out -27, which is the correct value. Does anyone have any ideas?
Because int8_t is the same as signed char, and char is not treated as a number by the stream. Cast into e.g. int16_t
std::cout << static_cast<int16_t>(value) << std::endl;
and you'll get the correct result.
This is because int8_t is synonymous to signed char.
So the value will be shown as a char value.
To force int display you could use
std::cout << (int) 'a' << std::endl;
This will work, as long as you don't require special formatting, e.g.
std::cout << std::hex << (int) 'a' << std::endl;
In that case you'll get artifacts from the widened size, especially if the char value is negative (you'd get FFFFFFFF or FFFF1 for (int)(int8_t)-1 instead of FF)
Edit see also this very readable writeup that goes into more detail and offers more strategies to 'deal' with this: http://blog.mezeske.com/?p=170
1 depending on architecture and compiler
Most probably int8_t is
typedef char int8_t
Therefore when you use stream out "value" the underlying type (a char) is printed.
One solution to get a "integer number" printed is to type cast value before streaming the int8_t:
std::cout << static_cast<int>(value) << std::endl;
It looks like it is printing out the value as a character - If you use 'char value;' instead, it prints the same thing. int8_t is from the C standard library, so it may be that cout is not prepared for it(or it is just typedefd to char).