-3

So. I am trying to convert a uint16_t (16 byte int) to class. To get the class member varaible. But it is not working as expected.


class test{
public:
    uint8_t m_pcp : 3; // Defining max size as 3 bytes
    bool m_dei : 1;
    uint16_t m_vid : 12; // Defining max size as 12 bytes

public:
    test(uint16_t vid, uint8_t pcp=0, bool dei=0) {
        m_vid = vid;
        m_pcp = pcp;
        m_dei = dei;
    }
};

int main() {
    uint16_t tci = 65535;
    test t = (test)tci;

    cout<<"pcp: "<<t.m_pcp<<" dei: "<<t.m_dei<<" vid "<<t.m_vid<<"\n";
    return 0;
}

Expected output:

pcp:1  dei: 1 vid 4095

The actual output:

pcp:  dei: 0 vid 4095

Also,

cout<<sizeof(t)

returns 2. shouldn't it be 4?

Am I doing something wrong?

Spencer
  • 1,924
  • 15
  • 27
rashi
  • 3
  • 2
  • Why should it be `4`? You have bitfields totaling 16 bits, so your class only need to be 2 bytes wide. – NathanOliver Oct 26 '22 at 12:18
  • Also note : bitfield memory layout is implementation defined. Thus memory layout may not match up with your expectations. Bitfields only guarantee correct arithmetic on the values (modulo, or signed overflow). So you will have to check what your compiler actually generates for your specific processor. https://en.cppreference.com/w/cpp/language/bit_field – Pepijn Kramer Oct 26 '22 at 12:20
  • 1
    You aren't casting `tci` to `test`, you are calling the constructor with default values. – Nelfeal Oct 26 '22 at 12:23
  • Re: "uint16_t (16 byte int)" -- should be 16 **bit** int. Same for all the comments about bitfield sizes; the numbers are the number of bits, not bytes. – Pete Becker Oct 26 '22 at 13:07

2 Answers2

1
test t = (test)tci;

This line does not perform the cast you expect (which would be a reinterpret_cast, but it would not compile). It simply calls your constructor with the default values. So m_vid is assigned 65535 truncated to 12 bits, and m_pcp and m_dei are assigned 0. Try removing the constructor to see that it does not compile.

The only way I know to do what you want is to write a correct constructor, like so:

test(uint16_t i) {
    m_vid = i & 0x0fff;
    i >>= 12;
    m_dei = i & 0x1;
    i >>= 1;
    m_pcp = i & 0x7;
}

Demo

Also I'm not sure why you would expect m_pcp to be 1, since the 3 highest bits of 65535 make 7.

Also, cout<<sizeof(t) returns 2. shouldn't it be 4?

No, 3+1+12=16 bits make 2 bytes.

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
-1

Your bitfields have 16 bits in total, so 2 bytes is correct for size. (compiler will pack together adjacent bitfields -- but be wary since may vary across compilers) Your constructor on a single uint16_t value assigns just 12 bits of the value to m_vid and 0 to the other members. The first 12 bits of 65535 are 4095, so the output is correctly as you note (NOTE: your comments on bitfields being bytes should read "bits"), but your expectation for the others is off. The constructor clearly says to provide a 0 value for them if not specified.