Archived

This topic is now archived and is closed to further replies.

WebsiteWill

sizeof() question

Recommended Posts

First off. Thanks to C-Junkie and others for help on this other topic. http://www.gamedev.net/community/forums/topic.asp?topic_id=170520 I took your advice and am making each packet class have virtual destructors and lookup functions. My plans thus far is to have the lookup function simply return a pointer to the structure that has to be sent over the network and also the size of the buffer. Each packet class contains a stucture that I call sInfo. The contents of sInfo will be overridden for each packet type except that the first three parameters will always be the same. Those are type, size and packetNumber respectfully. Each class will add new members to this structure as necessary. The whole class object itself will contain extra info like the senders IP address and Port as well as destination IP and Port (this derived from the base class as it''s generic to all packets going onto the queue). That information is outside of the structure because it''s not specifically sent over the network but the information is used by the network code. What I am planning to do with the lookup function is pass it two pass by reference parameters through which I can return a pointer to the sInfo structure as well as the size of the sInfo structure and also a pass by value parameter of the pointer to the packet in question. This way, only the networking class will have direct access to the packet queue directly, which is what I want. While coding this in I got to thinking. This method should easily allow me to use variable size packets for chat. At first I was going to allow players to send 128 or 256 character text strings. Which was sent would be determined by how much was typed before issuing the send command. But doing it the new way, I''d like a way to actually return the exact size of the sInfo structure. Example sInfo structure for a chat packet
struct
{
   int type;
   int size;
   int packetNum;
   string text;
}sInfo;
Now, because of the string container class I''m not sure if sizeof(sInfo) will work for this because according to it''s specification it won''t work with dynamically allocated arrays (which I think a string is). So even if I have a pointer to a packet like packet* p I don''t think sizeof(p->sInfo) would be correct if the structure has a string or other dynamic member in it. I don''t think anyway. So as you can probably guess by now, I''m looking for a way to return the exact size of the structure even if it has a queue or string, etc inside. Otherwise I''m back to specific chat packet sizes (64, 128, 256, etc). Any ideas? Thanks, Webby

Share this post


Link to post
Share on other sites
string is dynmically allocated, so it won''t work like you want it to... since the chat structure has only one string, you could do a nifty little hack like

struct{
int type;
int size;
int packetNum;
char text[512];
}sInfo;


This moves the string into the structure instead of dynamically allocated memory. (which wouldn''t send over the network like i think you''re trying to do)

Now, sizeof(sInfo) is always going to be the same value (probably 524 or so), however when we''re going to be transmitting this over the network, we don''t need to send all of it. Only as much as there is in the string, so...

if( originalString.size() > 511 )
// TOO BIG!
strncpy(sInfo.text,originalString.c_str(), 512);
sizeOfSInfoToBeTransmitted = sizeof(sInfo) - (511 - strlen(sInfo.text));


or something like that. someone will correct me if my really quick math there was wrong. anyway, this should transmit enough of sInfo to go right up to (er.. including) the null termination of text, which is all you need.

Share this post


Link to post
Share on other sites
what''s about switching to "class only" structure and then building into a "GetItemSize()" function ??

DJSnow
-----
this post is manually created and therefore legally valid without a signature

Share this post


Link to post
Share on other sites
quote:
Original post by WebsiteWill

So even if I have a pointer to a packet like packet* p I don't think sizeof(p->sInfo) would be correct if the structure has a string or other dynamic member in it.


I'm afraid that won't work anyway. Data members can't be virtual, so either you end up with the size of the struct in the base class (assuming it has one) or an error. Now if you only refer to the structure while inside member functions, then it will be fine, but then you don't need the pointer since it will be using the this pointer implicitly.

Edit: When I said it would be fine, I wasn't refering to your question about sizeof. I was just pointing out the inheritance issue regarding data members.


[edited by - SpaceRogue on July 25, 2003 9:28:02 PM]

Share this post


Link to post
Share on other sites
Hmmm.
If I have a structure like this
struct
{
int type;
string text;
}sInfo;

and I fill in the structure with some info and then cast a pointer to it what will I have?
I''ll have a pointer to the beginning of where my actual structure is stored into memory correct?

So I''m thinking that I can do something like this.

class packet
{
public:
struct
{
int type;
int size;
}sInfo;
};

class newPacket : public packet
{
public:
virtual void lookup(sInfo* psInfo, int &size)
struct
{
int type;
int size;
int string;
}sInfo; //Same as above but with differene members.

};

void newPacket::lookup(sInfo* psInfo, int &size)
{
psInfo = &this->sInfo;
size = sizeof(int)+sizeof(int)+string.size();
}

int main()
{
queue<packet*> myQueue;
myQueue.push(new newPacket(123, 123, "Here a string");
sInfo* myInfo;
int size;
packet* pPacket = myQueue.front();
pPacket->lookup(myInfo, size);
sendto(socket, myInfo, size, address, address_size);
return 0;
}


The call to lookup used above will call the lookup function that is specific to the newPacket class. I''ve tested that part with some basic code similar to the above. The problem I see with it right now is that I am passing it a pointer to sInfo. But which sInfo? Would there be a way to cast it to the local sInfo structure inside of the lookup function? I know the different structures work because I''ve tested the above and can indeed access the string member after popping it from the queue and casting it to the correct type. It''s the pointer that''s throwing me off.

The other way would be to pass the entire packet that was just popped fromt he queue to the lookup function (or pass a pointer to it at least) and have each lookup function call sendto as necessary. I wanted to stay away from that because it would produce a lot of extra code and would also take some of the network functionality out of the network class and place it inside of the various packet classes. I''d rather have one send function that is called and have it gather the information as necessary to send. This would make things tons easier to debug and add new packet types as necessary if I can figure out how to cast the pointer correctly.

Thanks,
Webby

Share this post


Link to post
Share on other sites
I think this might help:

http://www.parashift.com/c++-faq-lite/value-vs-ref-semantics.html#faq-31.2

(note: There''re TONS of good explanations there on how and why things are done certain ways in C++. I read the entire FAQ, and it taught it me quite a bit.)

Share this post


Link to post
Share on other sites
I think I got it working in a good manner. Please look at this and let me know if you see any holes. I realize that it''s very basic but I''m looking for the main functionality for now.

The first code here is just examples of two packet classes, the generic one and an actual one.

#include <string>
using namespace std;

class packet
{
public:
string sToAddr;
string sFromAddr;
int iToPort;
int iFromPort;
struct S
{
int iType;
int iSize;
int iPacketNumber;
}sInfo;

packet();
virtual packet(int type, int size, int packetNumber);
virtual void sendOn();
};
packet::packet()
{
}
packet::packet(int itype, int isize,int packetNumber)
{
sInfo.iType = itype;
sInfo.iSize = isize;
sInfo.iPacketNumber = packetNumber;
//Other initialization code to follow

}
void packet::sendOn()
{
//Send the packet here calling sendto(x,x,x,x) directly

}

/////////////////////////////////////////////

/////////////////////////////////////////////

class joepacket : public packet
{
public:
struct S
{
int iType;
int iSize;
int iPacketNumber;
int iStuff;
}sInfo;

joepacket();
virtual joepacket(int type, int size,int packetNumber, int stuff);
virtual void sendOn();
};
joepacket::joepacket()
{
}
joepacket::joepacket(int itype, int isize,
int packetNumber, int istuff)
{
sInfo.iType = itype;
sInfo.iSize = isize;
sInfo.iPacketNumber = packetNumber;
sInfo.iStuff = istuff;
}
void joepacket::sendOn()
{
//Send the packet here

}

This is a sample of the network code. It''s a class that houses the sendQueue in a private member.
Can add packets to the queue only by calling the addPacket function and passing it either a pointer to the desired packet or by using the constructor with new.
The send function simply pops a packet from the queue and calls the virtual sendOn() function of that packet. I''ve checked this and it does indeed call the appropriate function.

One main question I have is regarding the send() function. First I get the head pointer from the queue and then I pop the packet off of the queue completely. At this point the packet has been removed from the queue. Next I call the sendOn function of that packet andwhen it returns I call delete on the pointer. Am I correct here in thinking that the memory is now free because the call to delete will call that packets specific destructor? Thinking about it now, the destructors and constructors will probably all have to be virtual as well correct?

#include "PacketTest.h"
#include <queue>
#include <iostream.h>
using namespace std;

class network
{
public:
void send();
void addPacket(packet* myPacket);
private:
queue<packet*> sendQueue;
};

void network::addPacket(packet* myPacket)
{
sendQueue.push(myPacket);
}

void network::send()
{
packet* testPacket = sendQueue.front();
sendQueue.pop();
testPacket->sendOn();
delete testPacket;
}

This is just a sample driver file used to test the above. As far as I can tell, everything works correctly. I''d just like to know if any of you see any major or even minor bugs here.

#include <iostream.h>
#include <queue>
#include "Network.h"
using namespace std;

int main()
{
network myNetwork;

myNetwork.addPacket(new packet(123,234,432));
myNetwork.addPacket(new joepacket(111,222,333,444));

myNetwork.send();
myNetwork.send();

return (0);
}


Thanks for any tips, I''m finally getting it.
Webby

Share this post


Link to post
Share on other sites