C++ Same Name Different Type - c++

I have an anonymous union which contain a uint8_t and a bit field struct.
union
{
struct
{
uint8_t ID : 1;
uint8_t C : 4;
uint8_t RM : 1;
uint8_t SWRST : 1;
uint8_t STS : 1;
} ControlByte1;
uint8_t ControlByte1;
};
As you can see both the uint8_t and struct instances are called ControlByte1. What I'm trying to do is to have ControlByte1 be a uint8_t while being able to access its bits with ControlByte1.ID, ControlByte1.C, ControlByte1.RM, ControlByte1.SWRTS and ControlByte1.STS. As expected, when I write ControlByte1 = ...;, ... = ControlByte1; or function(ControlByte1);, the compilator has no way of knowing if I mean ControlByte1 as a uint8_t or struct. Is there any way to do this?
Thanks!
Edit 1:
I would just like them to have the same name because ControlByte1 is a one byte I2C control byte which contain ID, C, RM, SWRST and STS fields. I want to be able to access ControlByte1 as a byte and also access it's fields individually.
Edit 2:
I may have found a way by overloading the implicit type casting operator.
struct
{
uint8_t ID : 1;
uint8_t C : 4;
uint8_t RM : 1;
uint8_t SWRST : 1;
uint8_t STS : 1;
operator uint8_t*() {return (uint8_t *)this;}
operator uint8_t() {return *(uint8_t *)this;}
} ControlByte1;
I'm not sure if I'm doing the overloading correctly but it does compile, I haven't tried running my code yet.
uint8_t var1 = ControlByte1; // Compile
uint8_t *ptr1 = ControlByte1; // Compile
uint8_t *ptr2 = &ControlByte1; // Does not compile!!!
var1 = ControlByte1; // Compile
ptr1 = ControlByte1; // Compile
ptr2 = &ControlByte1; // Does not compile!!!
I'm guessing that &ControlByte1 does not compile because I need to overload the & operator too? There is no need to overload assignment operator because I do not assign anything directly to ControlByte1.
Edit 3:
This make more sense.
struct
{
uint8_t ID : 1;
uint8_t C : 4;
uint8_t RM : 1;
uint8_t SWRST : 1;
uint8_t STS : 1;
// For implicit casting to uint8_t
operator uint8_t() const
{
return(*(uint8_t *)this);
}
// For implicit casting to uint8_t *
uint8_t * operator &() const
{
return((uint8_t *)this);
}
} ControlByte1;

Related

Standard way of overlay flexible array member

So the server sends the data just as packed structures, so what only need to decode is to overlay the structure pointer on the buffer. However one of the structure is a dynamic array kind of data, but I learned that flexible array member is not a C++ standard feature. How can I do it in standard C++ way, but without copying like a vector?
// on wire format: | field a | length | length of struct b |
// the sturcts are defined packed
__pragma(pack(1))
struct B {
//...
};
struct Msg {
int32_t a;
uint32_t length;
B *data; // how to declare this?
};
__pragma(pack())
char *buf = readIO();
// overlay, without copy and assignments of each field
const Msg *m = reinterpret_cast<const Msg *>(buf);
// access m->data[i] from 0 to length
The common way to do this in C was to declare data as an array of length one as the last struct member. You then allocate the space needed as if the array was larger.
Seems to work fine in C++ as well. You should perhaps wrap access to the data in a span or equivalent, so the implementation details don't leak outside your class.
#include <string>
#include <span>
struct B {
float x;
float y;
};
struct Msg {
int a;
std::size_t length;
B data[1];
};
char* readIO()
{
constexpr int numData = 3;
char* out = new char[sizeof(Msg) + sizeof(B) * (numData - 1)];
return out;
}
int main(){
char *buf = readIO();
// overlay, without copy and assignments of each field
const Msg *m = reinterpret_cast<const Msg *>(buf);
// access m->data[i] from 0 to length
std::span<const B> data(m->data, m->length);
for(auto& b: data)
{
// do something
}
return 0;
}
https://godbolt.org/z/EoMbeE8or
A standard solution is to not represent the array as a member of the message, but rather as a separate object.
struct Msg {
int a;
size_t length;
};
const Msg& m = *reinterpret_cast<const Msg*>(buf);
span<const B> data = {
reinterpret_cast<const B*>(buf + sizeof(Msg)),
m.length,
};
Note that reinterpretation / copying of bytes is not portable between systems with different representations (byte endianness, integer sizes, alignments, subobject packing etc.), and same representation is typically not something that can be assumed in network communication.
// on wire format: | field a | length | length of struct b |
You can't overlay the struct, because you can't guarantee that the binary representation of Msg will match the on wire format. Also int is at least 16 bits, can be any number of bits greater than 16, and size_t has various size depending on architecture.
Write actual accessors to the data. Use fixed width integer types. It will only work if the data actually point to a properly aligned region. This method allows you to write assertions and throw exceptions when stuff goes bad (for example, you can throw on out-of-bounds access to the array).
struct Msg {
constexpr static size_t your_required_alignment = alingof(uint32_t);
char *buf;
Msg (char *buf) : buf(buf) {
assert((uintptr_t)buf % your_required_alignment == 0);
}
int32_t& get_a() { return *reinterpret_cast<int32_t*>(buf); }
uint32_t& length() { return *reinterpret_cast<uint32_t *>(buf + sizeof(int32_t)); }
struct Barray {
char *buf;
Barray(char *buf) : buf(buf) {}
int16_t &operator[](size_t idx) {
return *reinterpret_cast<int16_t*>(buf + idx * sizeof(int16_t));
}
}
Barray data() {
return buf + sizeof(int32_t) + sizoef(uint32_t);
}
};
int main() {
Msg msg(readIO());
std::cout << msg.a() << msg.length();
msg.data()[1] = 5;
// or maybe even implement straight operator[]:
// msg[1] = 5;
}
If the data do not point to a properly aligned region, you have to copy the data, there is no possibility to access them using other types then char.

Creating constructor for a struct(union) in C++

What is the best way to create a constructor for a struct(which has a union member, does it matter?) to convert uint8_t type into the struct?
Here is my example to clarify more:
struct twoSixByte
{
union {
uint8_t fullByte;
struct
{
uint8_t twoPart : 2;
uint8_t sixPart : 6;
} bits;
};
};
uint32_t extractByte(twoSixByte mixedByte){
return mixedByte.bits.twoPart * mixedByte.bits.sixPart;
}
uint8_t tnum = 182;
print(extractByte(tnum)); // must print 2 * 54 = 108
P.S.
Finding from comments & answers, type-punning for unions is not possible in C++.
The solutions given are a little bit complicated specially where there are lots of these structures in the code. There are even situations where a byte is divided into multiple bit parts(more than two). So without taking advantage of unions and instead using bitsets ans shifting bits adds a lot of burden to the code.
Instead, I managed for a much simpler solution. I just converted the type before passing it to the function. Here is the fixed code:
struct twoSixByte
{
union {
uint8_t fullByte;
struct
{
uint8_t twoPart : 2;
uint8_t sixPart : 6;
} bits;
};
};
uint32_t extractByte(twoSixByte mixedByte){
return mixedByte.bits.twoPart * mixedByte.bits.sixPart;
}
uint8_t tnum = 182;
twoSixByte mixedType;
mixedType.fullByte = tnum;
print(extractByte(mixedByte)); // must print 2 * 54 = 108
Unless there is a pressing need for you to use a union, don't use it. Simplify your class to:
struct twoSixByte
{
twoSixByte(uint8_t in) : twoPart((in & 0xC0) >> 6), sixPart(in & 0x3F) {}
uint8_t twoPart : 2;
uint8_t sixPart : 6;
};
If there is a need to get the full byte, you can use:
uint8_t fullByte(twoSixByte mixedByte)
{
return ((mixedByte.twoPart << 6) | mixedByte.sixPart);
}
You could avoid the union and type punning and use a struct with the relevant member function. Note that we don't need a constructor if the struct is regarded as an aggregate to be initialized:
#include <cstdint>
struct twoSixByte {
uint8_t fullByte; // no constructor needed, initializing as an aggregate
uint32_t extractByte(){
return ((fullByte & 0b1100'0000) >> 6) * (fullByte & 0b0011'1111);
}
};
int main()
{
twoSixByte tnum{182};
auto test = tnum.extractByte(); // test == 2 * 54 == 108
}

sizeof(struct) returns a SMALLER than expected value?

I have this c++ structure:
struct Packet
{
uint32 MessageCount;
uint32 Length;
uint32 FieldValue;
union PacketHeader
{
uint32 typeInfo;
struct MagicVersion
{
uint8 MagicNumber[3];
uint8 Version;
};
};
Data * Payload(void) { return reinterpret_cast< Data * >(this + 1U); }
Data const * Payload(void) const { return reinterpret_cast< Data const * >(this + 1U); }
Packet * nextPacket(void) { return reinterpret_cast< Packet * >(this + 1U) + Length; }
Packet const * nextPacket(void) const { return reinterpret_cast< Packet const * >(this + 1U) + Length; }
};
Then sizeof(Packet) in MSVC++ returns 12 instead of 16 which is what I expect.
The weird thing is of course that this is smaller that the expected value. Had it been bigger it could be because of alignment issues.
What am I missing?
TIA
Why do you think it should be bigger?
It contains 3 uint32 with no virtual methods, that's exactly 12 bytes.
The union doesn't count, since it's a type, it contains no member of that type.
If you want your class to contain a single instance of the union, which contains a single instance of the struct, you should write:
struct Packet
{
uint32 MessageCount;
uint32 Length;
uint32 FieldValue;
union
{
uint32 typeInfo;
struct
{
uint8 MagicNumber[3];
uint8 Version;
} /* MagicVersion */;
};
} /* PacketHeader */;
The names within /**/ are optional, you can either specify them or not. If you do, you have to access their members using the name of the union/struct, otherwise you'll have a flat Packet struct.

PC-lint on switch case labels: Violates MISRA C++ 2008 Required Rule 5-0-12

//some static const variables are defined
static const uint8_t FirstData = 1;
static const uint8_t SecondData = 2;
//some switch case
switch (Numdata) //Numdata is either FirstData, SecondData
{
case FirstData:
//some code
case SecondData:
//some code
}
// Now PC-lint complaints for this "Note 1960: Violates MISRA C++ 2008 Required Rule 5-0-12, Disallowed use of non-numeric value in a case label"
So the question is why PC-lint does not consider static const members as Numeric value?
Is it a good idea to explicitly type cast case labels (which should resolve this) ?
what type do the case labels need to be type cast to? Will just uint8_t do?
Some other way to exempt this Lint issue ?
Try using an enum, as they are "known", using the following code for example, the second function does not have the issue.
#include <cstdint>
namespace testa
{
static const uint8_t FirstData = 1;
static const uint8_t SecondData = 2;
int32_t func_A(uint8_t Numdata)
{
int32_t ret = 0;
switch (Numdata) //Numdata is either FirstData, SecondData
{
case FirstData:
ret = 1;
case SecondData:
ret = 2;
}
return ret;
}
}
namespace testb
{
enum data {
FirstData,
SecondData
};
int32_t func_B(data Numdata)
{
int32_t ret = 0;
switch (Numdata) //Numdata is either FirstData, SecondData
{
case FirstData:
ret = 1;
case SecondData:
ret = 2;
}
return ret;
}
}
int32_t main(int32_t, int8_t*[])
{
int32_t z = 0;
z += testa::func_A(testa::FirstData);
z += testa::func_A(testa::SecondData);
z += testb::func_B(testb::FirstData);
z += testb::func_B(testb::SecondData);
return z;
}
The rule says : "[Explicitly] signed char and unsigned char type shall only be used for the storage and use of numeric values." I assume this disallows use as labels, and the lint error message is badly worded. I see nothing wrong with it and would just disable the warning for that code, or, if necessary, for the whole file.

Data structures with different sized bit fields

If I have a requirement to create a data structure that has the following fields:
16-bit Size field
3-bit Version field
1-bit CRC field
How would I code this struct? I know the Size field would be an unsigned short type, but what about the other two fields?
First, unsigned short isn't guaranteed to be only 16 bits, just at least 16 bits.
You could do this:
struct Data
{
unsigned short size : 16;
unsigned char version : 3;
unsigned char crc : 1;
};
Assuming you want no padding between the fields, you'll have to issue the appropriate instructions to your compiler. With gcc, you can decorate the structure with __attribute__((packed)):
struct Data
{
// ...
} __attribute__((packed));
In Visual C++, you can use #pragma pack:
#pragma pack(push, 0)
struct Data
{
// ...
};
#pragma pack(pop)
The following class implements the fields you are looking for as a kind of bitfields.
struct Identifier
{
unsigned int a; // only bits 0-19 are used
unsigned int getSize() const {
return a & 0xFFFF; // access bits 0-15
}
unsigned int getVersion() const {
return (a >> 16) & 7; // access bits 16-18
}
unsigned int getCrc() const {
return (a >> 19) & 1; // access bit 19
}
void setSize(unsigned int size) {
a = a - (a & 0xFFF) + (size & 0xFFF);
}
void setVersion(unsigned int version) {
a = a - (a & (7<<16)) + ((version & 7) << 16);
}
void setCrc(unsigned int crc) {
a = a - (a & (1<<19)) + ((crc & 1) << 19);
}
};