join structs in c++? [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to create an ethernet packet plus TCP/IP payload, for that I've create three structs as follows: ethernet struct, tcp struct and ip struct all these structs are filled with valid information but I don't know what I need to do now, I need join the spared structs into a plain struct (such as an array) since I want to inject the constructed packet and all bits need to be consecutive.

Define a new class, make these three structs its instance variables, code setters and getters for the class. You may want to pay attention to const correctness when writing getters - mark getters with const keyword.
struct EthStruct1
{
// ...
};
struct EthStruct2
{
// ...
};
struct EthStruct3
{
// ...
}
class newClass
{
public :
newClass(){}
~newClass(){}
// Add functions to get and set values in A. Mark getters with const for immutability of receiver
// Add functions to get and set values in B. Mark getters with const for immutability of receiver
// Add functions to get and set values in C. Mark getters with const for immutability of receiver
private:
EthStruct1 A;
EthStruct2 B;
EthStruct3 C;
};

Declare a byte array whose size is the sum of the sizes of the three structs. Then copy the raw bytes of each struct into the array where needed. Then use the array as needed.
struct ethernet
{
...
};
struct tcp
{
...
};
struct ip
{
...
};
ethernet e;
tcp t;
ip i;
unsigned char arr[sizeof(e)+sizeof(t)+sizeof(i)];
memcpy(&arr[0], &e, sizeof(e)];
memcpy(&arr[sizeof(e)], &t, sizeof(t)];
memcpy(&arr[sizeof(e)+sizeof(t)], &i, sizeof(i)];
Alternatively:
struct ethernet
{
...
};
struct tcp
{
...
};
struct ip
{
...
};
struct pkt
{
ethernet e;
tcp t;
ip i;
};
ethernet e;
tcp t;
ip i;
unsigned char arr[sizeof(pkt)];
pkt *p = (pkt) &arr[0];
p->e = e;
p->t = t;
p->i = i;

I like to use union when converting structures to byte arrays. Be sure your compiler is using single-byte structure alignment... for the Windows compiler I know you can use #pragma pack(push,1) to start that and #pragma pack(pop) to terminate. I will use this way in my example.
#pragma pack(push,1) // start single-byte struct alignment
struct EthernetInfo
{
// data here
};
struct TCPInfo
{
// data here
};
struct IPInfo
{
// data here
};
union Packet
{
struct {
struct EthernetInfo ethernetInfo;
struct TCPInfo tcpInfo;
struct IPInfo ipInfo;
} AsPacket;
unsigned char AsBytes[sizeof(EthernetInfo) + sizeof(TCPInfo) + sizeof(IPInfo)];
};
#pragma pack(pop) // revert to whatever struct alignment was in use before

Related

C++ Variable Array length within struct

hey guys i trying to write a handler for a generalised master/slave communication.
The implementation should be able to handle different communication types (USB/modbus/SPI etc.)
For every communication type a new instance of this class is created.
Each communication way has another max datalength limit. Every received packed (byte array) is mapped on a struct
class My_Communication
{
struct My_Struct
{
//some Header Information
byte data[max_data_length]; ///< this array has a different datalength.
}
}
Can i set the (const) datalength within a class constructor?
If you don't know the array size at compile time you should use std::vector:
class My_Communication
{
struct My_Struct
{
//some Header Information
std::vector< byte > data;
};
};
If you know the size at compile time then use std::array in a templated class:
class My_Communication
{
template < size_t DataSize >
struct My_Struct
{
//some Header Information
std::array< byte, DataSize > data;
};
};

Inheriting a packed C struct

I am using a third party library (mavlink) that defines a number of structs that are all tagged with __attribute__((packed)) so they can be efficiently be transmitted across a serial connection (it is written in C and I am using it in a C++ application). When I receive and reconstruct them I would like to add a time stamp field to them. I think the simplest way is to create a new struct that inherits the existing struct. i.e. in the mavlink library this struct is defined:
MAVPACKED(
typedef struct __mavlink_heartbeat_t {
uint32_t custom_mode;
uint8_t type;
uint8_t autopilot;
uint8_t base_mode;
uint8_t system_status;
uint8_t mavlink_version;
}) mavlink_heartbeat_t;
where MAVPACKED is a macro that applies __attribute__((packed)). sizeof(mavlink_heartbeat_t) returns 9. If I define
struct new_heartbeat_t : mavlink_heartbeat_t
{
uint64_t timestamp;
};
sizeof(new_heartbeat_t) returns 24, so it looks like 7 padding bytes are added (I would assume to end of mavlink_heartbeat_t so that timestamp start at byte 16.)
Are there any gotchas or things to be aware of when doing this or is there a better way?
Inheritance is a is a kind of relationship.
Is the local representation of a heartbeat really a kind of wire message? I doubt it.
But it might reasonably contain one.
I would encapsulate it something like this:
#include <cstdint>
#include <cstddef>
typedef struct __attribute__((packed)) __mavlink_heartbeat_t {
uint32_t custom_mode;
uint8_t type;
uint8_t autopilot;
uint8_t base_mode;
uint8_t system_status;
uint8_t mavlink_version;
} mavlink_heartbeat_t;
extern std::uint64_t now();
void sync_fetch_data(mavlink_heartbeat_t&);
void foo(uint8_t);
struct local_heartbeat
{
mavlink_heartbeat_t const& get_io_buffer() const {
return io_buffer_;
}
mavlink_heartbeat_t& prepare_receive() {
request_timestamp_ = now();
return io_buffer_;
}
void complete_receive() {
response_timestamp_ = now();
}
std::uint64_t get_response_timestamp() const {
return response_timestamp_;
}
private:
// stuff in here might have suspect alignment
mavlink_heartbeat_t io_buffer_;
// but these will be aligned for optimal performance
std::uint64_t request_timestamp_;
std::uint64_t response_timestamp_;
};
int main()
{
// create my local representation
local_heartbeat hb;
// prepare it to receive data
auto& buffer = hb.prepare_receive();
// somehow populate the buffer
sync_fetch_data(buffer); // could be async, etc
// notify the object that reception is complete
hb.complete_receive();
// now use the local representation
foo(hb.get_io_buffer().system_status);
}

how to detect or avoid using C++ uninitialized pointer? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I got an uninitialized pointer problem today. unfortunately, it caused core dump after it released.
here is the sample code, and the function print_request() is new code, and this function could be used by several other functions:
// def.h
struct INFO {
uint32_t val1;
uint32_t val2;
};
struct INFO_LIST {
uint32_t id;
struct INFO * data;
};
// util.cpp
void print_request(const struct INFO_LIST req)
{
fprintf(stdout, "%u\t%u\t%u\n", req.id, req.data->val1, req.data->val2);
}
// A.cpp
int parse_ie(...)
{
// ...
struct INFO_LIST req;
req.id = 10;
req.data = new INFO();
req.val1 = 101;
req.val2 = 102;
print_request(req);
// ...
}
// B.cpp
int parse_chrome(...)
{
// ...
struct INFO_LIST req;
req.id = 20;
print_request(req); // core dump here!
// ...
}
here is what I have done:
I have wroten the unit test for print_request(), but I forgot there is an uninitialized pointer while function parse_chrome() use it.
I analyzer the code by using the static code analyzer tool, for example, cppcheck, and there is no error or warning.
it is still ignored after code reviewing.
so, I want to know:
is there any good tool to detect the uninitialized pointer in C++?
how to avoid using uninitialized pointer in C++?
any suggestion would be appreciated, thank you!
PS, I want to write uniform functions to call the pointer, but it would cost much time.
PPS. sorry, variable "req" is not a pointer. my fault.
First, add a default constructor to INFO_LIST:
struct INFO_LIST {
uint32_t id;
struct INFO * data;
INFO_LIST() : id(0), data(nullptr) { ; }
};
Second: Throw an exception in print_request:
// util.cpp
void print_request(const struct INFO_LIST req)
{
if (! req.data->val1 || ! req.data->val2)
throw (std::runtime_error ("Uninitialized pointers"));
fprintf(stdout, "%u\t%u\t%u\n", req.id, req.data->val1, req.data->val2);
}
If you want to catch this at compile time:
struct INFO_LIST {
uint32_t id;
struct INFO * data;
INFO_LIST (struct INFO* d) : data(d) { ; }
private:
INFO_LIST () { ; }
};
Now you will get an error at compile time if you try to construct an INFO_LIST without initializing the data pointer.
You have created a struct pointer at line INFO_LIST * req;, remove a * to create a struct instead. Currently you are using a bare pointer (of type struct INFO_LIST) to nothing.
How avoid using a c++ empty pointer?
Your code looks like c, to me. The languages are different, pick one or the other.
As to your question title:
In C++, you can use the non-nullptr value tested as:
if(ptr) ptr->doSomething();
else doSomethingElse();
NOTE that pointers are POD, and must be explicitly initialized.
So
MyObject* ptr = new MyObject; // default ctor
assert(nullptr != ptr); // check for success
or
MyObject* ptr = nullptr;
// later code sets the pointer to something
I prefer to use the slightly more clear:
if(nullptr != ptr) ptr->doSomething();

Receiving flexible array over socket

I got a codebase which used to transfer several kinds of message on socket to another process and used a union for that
#define maxlen 60
typedef struct
{
TYRES t[MAXLEN];
} TYRE_T;
typdef struct
{
TUBES t[MAXLEN];
}TUBES_T;
typedef struct
{
TYPE t[MAXLEN];
} TYPE_T;
typedef union
{
TYRE_T tyres;
TUBES_T tubes;
TYPE_T type;
} messageunion;
typedef struct
{
int code;
messageunion msg;
} socketmessage_t;
enum msgtype
{
INVALID = -1;
TYRES,
TUBES,
TYPES
};
//On clientside
processMessage(socketmessage_t* msg)
{
switch(msg->code)
{
....
}
}
Now MAXLEN is not a macro but it will be run time variable evaluated by program. so I changed all array members to flexible array like this
typedef struct
{
int size;
TYRES t[];
}
My question is almost all socket functions needs size of buffer to receive message so how to calculate that size here?
Thanks
First you should probably start using fixed-size integers, like uint32_t (from <cstdint>) for the sizes and message types.
Then the receiving application know how much to read to get the message type, and how much to read to get the size. Then simply read the specified number of bytes into the correct structure.
The important thing is that all structures in the union must start with a size member.

How to set data with 0 in C++? [duplicate]

This question already has answers here:
Initializing an object to all zeroes
(12 answers)
Closed 9 years ago.
In C we set data to 0 with memset() function (Not only for the initialization).
My data could be changed by another method and I want to reuse it and then I want to set it to 0 before reusing it
Are there another way to set data to 0 in C++ other than memset()?
class MYClass : public NameSpace::ParentClass {
private:
struct mystruct data
public:
void method();
};
void MYClass::method() {
memset(&data, 0, sizeof(data)); // it's the C way. Are there another way in C++
}
In C++ you would invoke the constructor of an object, or the initialiser for primitive constructor-less objects.
Re-initialisation should actually happen very rarely (don’t reuse variables, create new ones! It makes the program flow clearer) – but when you need it you can just re-assign a new object:
data = mystruct();
It is ok to use memset on POD types, otherwise initialization must be done using constructor.
The C++ way of zeroing should look like the following:
struct mystruct
{
int i;
void Reset();
}
class MYClass : public NameSpace::ParentClass
{
private:
mystruct data
public:
void method();
};
void mystruct::Reset()
{
i = 0;
}
void MYClass::method()
{
data.Reset();
}