2

to read bitgroups, I've written a little function for myself, which reads a bit group and returns the value. Actually, I thought the appended example should lead to an overflow in the following command

(BitGroupMask << BitGroupPosition)

According to the standard, intermediate results are interpreted as integers. However, the result is correct for all tested values. Apparently, the compiler checks the largest data type in the entire Expression. At least, my guess.

My question: Is the behavior dependent on the compiler or is it defined in the C++ standard?

Code:

#include <iostream>
#include <bitset>


using namespace std;


uint64_t Variable{0b1011111111111111111111111111111111111111111111111111111111111111ULL};
uint8_t GMask{0b1111};
uint8_t GPos{60};


template <typename VarType, typename MaskType>
inline VarType readBitGroup(VarType Var, MaskType BitGroupMask, MaskType BitGroupPosition)
{
    //return (VarType)((Var & ((VarType)BitGroupMask << BitGroupPosition)) >> BitGroupPosition);
    return ((Var & (BitGroupMask << BitGroupPosition)) >> BitGroupPosition);
}


int main()
{
    cout << std::bitset<64>(Variable) << std::endl;
    cout << std::bitset<4>(readBitGroup(Variable, GMask, GPos)) << std::endl;
    return 0;
}
4
  • What is the output you expect and the output you get? Commented Sep 28, 2017 at 13:12
  • I do not think this is minimal example. You have a lot of unrelevant code here. Here is what I think what you had to post gist.github.com/anonymous/4f6367a66920f5b7988b9ceba6a78684 Commented Sep 28, 2017 at 13:51
  • @ArtemyVysotsky: You can even use online ide instead of dummy github: Demo. Commented Sep 28, 2017 at 14:24
  • @ Yunnosch I expect 0b1011 and the result is correct Commented Sep 28, 2017 at 17:45

2 Answers 2

2

The code in question is

uint8_t GMask{0b1111};
uint8_t GPos{60};
... (GMask << GPos) ...

If I correctly read the standard

The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

Your uint_8 operands are promoted and then shift occurs.

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (7.15) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

The second quote specifies that values are promoted to int - since it is big enough to represent both values 15 and 60.

And then - going back to first quote we see that The behavior is undefined

So it is your responsibility to cast left operand of the shift to the type big enough to store the result of the shift.

Sign up to request clarification or add additional context in comments.

Comments

1

Yes you are right the behaviour is undefined. With the following values I get a wrong result:

uint64_t Variable{0b1111111110111111111111111111111111111111111111111111111111111111ULL};
uint8_t GMask{0b1111};
uint8_t GPos{52};

So I extended the line to

return ((Var & ((VarType)BitGroupMask << BitGroupPosition)) >> BitGroupPosition);

Now it's working. Thanks for your help!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.