Casting a structure to another

Hi,

I have a structure that is allocated by malloc

My first structure

struct TEST_STRUCT
{
int ID;
int x;
int i;
int y;
int z;

};

second structure

struct FILE_HEADER {
wchar_t Name[10];
int Size;


};

struct TEST_STRUCT* MemAllocated;
MemAllocated = static_cast<struct TEST_STRUCT*>(malloc(sizeof TEST_STRUCT + sizeof FILE_HEADER));
memset(MemAllocated, 0, sizeof TEST_STRUCT + sizeof FILE_HEADER);


How can I make FILE_HEADER structure points to MemAllocated + TEST_STRUCT?

I want to do MemAllocated + sizeof TEST_STRUCT->Name
Last edited on
I would skip all the nonsense and just say
unsigned char* cp = malloc(sizeof TEST_STRUCT + sizeof FILE_HEADER);
file_header * fh = (file_header*)(cp);
test_struct * ts = (test_struct*)(&cp[sizeof(file_header));
where cp is both of them together and fh * ts are the offsets cast out to their types.

but better to let the compiler deal with all this crap.
struct meta
{
test_struct ts;
file_header fh;
};
meta * mp = malloc(...

meta may be slightly (no more than 1 integer's worth) larger than doing it yourself depending on your compiler settings. but jacking everything into a byte array by hand is a LOT of management -- they use pages instead of best fit blocks for a reason at the OS level...
if you need it exactly due to a binary file or something, there are better ways to do this.
and why are you using the C memory tools?
Last edited on
Thanks for the reply.
I have also thought about doing this combining both structures into a main structure but I wanted them separated because FILE_HEADER is not always there. The TEST_STRUCT is always there but FILE_HEADER can be another structure depending on the data. I am sending a file over network so there could be different struct below TEST_STRUCT.

I couldn't see a way to create a whole sub-struct as a UNION.
For C memory tools, It's only a debug version for testing. I know I should be using New keyword.

I also solved the issue by doing
struct FILE_HEADER *FileHeader = (struct FILE_HEADER*)&MemAllocated + sizeof TEST_STRUCT;

If you know a better approach, I would be listening.
For C memory tools, It's only a debug version for testing. I know I should be using New keyword.


I would avoid using new , unless it is in a RAII class (new in the ctr, delete in the dtr). Instead, use an STL container or smart pointer if you really need it. Especially don't use new to obtain a pointer.
there are 'better' c++ approaches with the big guns of inheritance, polymorphism, and so on. These are better if your real problem is very complicated. If the real problem is simple, this may save you a lot of design and implementation headaches esp if you don't know those ideas pretty well.

the simple C-ish solution is still that union.
this now looks like :

union u
{
file_header fh;
somthing_else se;
};

struct meta
{
test_struct ts;
somenum type; //type of the thing below:
u anything_else; //variant, union, whatever -- follow mbozzi's lead here.
//it could even be just a char array that you cast to the desired type.
};

and now you have a container of meta objects, like before.

it still uses excess memory if you have ts by itself and no second part. the only way to avoid that with these simple C like ideas is to have the second piece be a void pointer, null if empty. If you make it a pointer, it can't be a solid block of memory. I do not know any way in c or c++ to inject a variable wad of memory into a struct: the struct MUST have a fixed size at compile time, so either you have extra space to hold something else and keep it all in a solid block, or you have a pointer, which makes it not a solid block but the attached second item can be empty. If that is what you are asking for, no can do -- or at least I don't know a way to do it and it seems dangerous to try (sizeof canna be trusted if you do that). ***

other handy stuff:
remember that you can define a cast operator, so you can set up a cast from a meta to a type, eg ts = (test_struct)(m); //m is a meta

remember as well that the first part of a struct is a direct memory byte overlay. That is, if struct a and struct b both had a test_struct as the first member, then a memcpy of one to the other or a pointer cast of one to the other can use/copy/whatever *only* the test_struct portion safely. I don't know if that is useful or not, it would be if you defined multiple meta type objects each with a test_struct as the first item...? That would be a weird design -- it has merits, but it would be risky (easy to access a nonexistent thing and bug up).

questions:
how complicated is your real problem? (how many actual types, etc)
are we solving an XY? Why do you want the memory packed so tightly, and what need do you have that the 2 items are in one block of memory?


*** actually there is a way. you can malloc more than you need and keep the size and type both as a variable in the struct. then the second part is just raw bytes after the test_struct part, and they could be zero length. But like I said, sizeof would now be wrong, and I dunno if you can swindle c++ to overload that to give the right answer or not. This is NOT something I would be willing to do other than to show off or annoy people -- it is a pure hack. If you are going to hack anyway, you may not even need the size, its probably in front of the block of memory somewhere or stowed some place you can get it from.
Last edited on
I would avoid using new , unless it is in a RAII class (new in the ctr, delete in the dtr). Instead, use an STL container or smart pointer if you really need it. Especially don't use new to obtain a pointer.


Very good point. Smart pointer seems a good choice here.

@jonnin

Maybe I did not explain it very well but here is what I meant
The buffer is always going to be fixed size which will always be larger than all structs. For eg, 0x2000 bytes in size. This is the bulk buffer used on socket recv (call it recvBuff). The very top of this buffer is PACKET_HEADER. This will always be present to identify packet in TCP. It is just an application message framing protocol. Here is a clearer version of the code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct PACKET_HEADER
{
	USHORT ID;
	USHORT Size;
	int ErrorNumber;

};

struct ERROR_HEADER
{
	int Number;

};

struct FILE_HEADER {
	wchar_t Name[10];
	int Size;
};


Now when returning from recv call,

recvBuff will be containing PACKET_HEADER + either FILE_HEADER, or PACKET_HEADER. This will be dependent on PACKET_HEADER.ErrorNumber

ie
1
2
3
4
5
6
7
if (recvBuff->PACKET_HEADER.ErrorNumber == 0)

recvBuff + sizeof PACKET_HEADER //will be pointing to FILE_HEADER.

else

recvBuff + sizeof PACKET_HEADER //will pointing to ERROR_HEADER. 


As you can see it's very simple problem. For now, not sure how to forward/cast this recvBuffer to point to next structure.
Last edited on
My understanding is that you want to reinterpret a chunk of memory that you got from the network, as a struct. This is not a good idea because
a. the layout of class types is implementation-defined;
b. the alignment requirement of each object type is implementation-defined; and
c. native (host) byte order is implementation-defined.
The approach you are taking might work, but it is exceedingly fragile.

To solve the problem properly, you should use memcpy to fill out your object using the data from the buffer:

For example

1
2
3
4
5
6
7
8
9
10
11
12
13
// The choice of unsigned char* is deliberate
unsigned char *recv_buf = 
  static_cast<unsigned char*>(malloc(size)) // malloc or new[]
ssize_t recv_bytes = recv(fd, recv_buf, size, flags);
// TODO: error checking
PACKET_HEADER pkt_head;
// pull the members of pkt_head out of the buffer:
memcpy(&pkt_head.ID, recv_buf + 0, sizeof pkt_head.ID); 
pkt_head.ID = ntohs(pkt_head.ID);
memcpy(&pkt_head.Size, recv_buf + 2, sizeof pkt_head.Size);
pkt_head.Size = noths(pkt_head.Size);
// TODO: handle signed int PACKET_HEADER::ErrorNumber as required
// ... 


Instead of memcpy and ntohl you could also use the extract_u?_be functions from the last post in this thread, which may save a few lines of code:
https://www.cplusplus.com/forum/lounge/279954/2/#msg1211823

Last edited on
A few different points:
1. You have to pack your structs as the network version won't have alignment filler bytes.
2. Do you need to fixup the byte ordering of the short and int members? You will if one host is, say arm and the other is intel. If you're doing anything other than a school project, you have to.
3. You can read the header, then read the payload. Thus no dynamic allocations. Just because they're available in the TCP stream, doesn't mean you have to read everything at once. UDP? then yes, you have to read the whole message, but TCP is a stream protocol, you read what you want to process.
4. Finally, int doesn't specify the actual type used, so it's unsuitable for network programming, where different hosts can have different definitions of int. Remember:
 
sizeof(short) <= sizeof(int) <= sizeof(long)


Your definitions should look something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma pack(push)
#pragma pack(1)

struct PACKET_HEADER {
	std::uint16_t ID;
	std::uint16_t Size;
	std::int32_t ErrorNumber;
};

struct ERROR_HEADER {
	std::int32_t Number;
};

struct FILE_HEADER {
	wchar_t Name[10];
	std::uint64_t Size;
};

#pragma pack(pop) 


That will allow you to write code like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PACKET_HEADER hdr;
ssize_t nbytes = ::recv(s, &hdr, sizeof(hdr), 0);

hdr.ID = ntohs(hdr.ID);
hdr.Size = ntohs(hdr.Size);
hdr.ErrorNumber = ntohl(hdr.ErrorNumber);

switch (hdr.ErrorNumber) {
    case WANT_ERROR_HEADER: {
        ERROR_HEADER errHdr;
        nbytes = ::recv(s, &errHdr, sizeof(errHdr), 0);
        process(errHdr);
    }
    break;
    case WANT_FILE_HEADER: {
        ERROR_FILE fileHdr;
        nbytes = ::recv(s, &fileHdr;, sizeof(fileHdr), 0);
        process(fileHdr;);
    }
    break;
} 
Last edited on
My understanding is that you want to reinterpret a chunk of memory that you got from the network, as a struct. This is not a good idea because
a. the layout of class types is implementation-defined;
b. the alignment requirement of each object type is implementation-defined; and
c. native (host) byte order is implementation-defined.
The approach you are taking might work, but it is exceedingly fragile.


This is very correct. I have read about this also and it's exactly like you described it.

3. You can read the header, then read the payload. Thus no dynamic allocations. Just because they're available in the TCP stream, doesn't mean you have to read everything at once. UDP? then yes, you have to read the whole message, but TCP is a stream protocol, you read what you want to process.


The source codes I read where implementing a fixed number of bytes to read, e.g, 0x2000 as a reading network buffer size. I have read somewhere that by doing your way we may end up with some performance penalty since we are now issuing more unnecessary recv calls on the socket. Although it will easy get complicated once recv gets more than a message frame at once which then you must also take that into account. Would like to read about comparing the two.

But I gotta say that you all have great knowledge. Although both of my projects were going to be platform specific, I have learned new terms from this topic, something they never teach in a college.
Last edited on
Topic archived. No new replies allowed.