Thread: Getting int32 from char

  1. #1
    Registered User
    Join Date
    Aug 2006
    Posts
    28

    Getting int32 from char

    Hi there,

    I'm new to c++ and these forums, so dont get too complex with me

    Basically, i'm trying to build a program to communicate with a gameserver. When recieving data from the server a 'header' packet is sent first, 8 bytes in length. The first 4 bytes are an int32 value representing the number of bytes that will be sent in the 'body'. The last 4 are also an int32 value of a handle which is used for asynchronous communication.

    I have been able to put together a simple program which can connect to the server and recieve the handshake. To do this I used the handy socket programing tutorial found here. The method it describes for recieving data uses the recv function...

    Code:
    int recv(int sockfd, void *buf, int len, unsigned int flags);
    However, despite the fact it states buf is of void type (I assume that means it will take more than one type), I can only seem to make buf as a char type or the compiler will complain. This does not matter for the handshake because a) I know the exact length of it, and b) the header is only 4 bytes as it requires no handle.

    To continue with my programing I need a way to get the 8 bytes from the header into 2 seperate int values. Any suggestions would be appreciated

  2. #2
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    I'm not too sure about recv() but I'd guess you could probably create a structure
    Code:
    struct header {
       __int32  bodySize;
       __int32  otherStuff;
    };
    ...and then just cast that as a char* and pass that to recv
    Code:
    header myHeaderData;
    recv(sockDesc, (char*)myHeaderData, 64, 0);
    I wouldn't quote me on that, though...

    Try it and see if it works.
    Sent from my iPadŽ

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    If you casted it to anything, it would be void*, I think.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    And the void* cast is implicit, so you don't cast it at all.

    Oh, and don't explicitly pass the size. Use the sizeof operator.
    Code:
    header myHeaderData;
    recv(sockDesc, &myHeaderData, sizeof(myHeaderData), 0);
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    Aug 2006
    Posts
    28
    Quote Originally Posted by SlyMaelstrom
    I'm not too sure about recv() but I'd guess you could probably create a structure
    Code:
    struct header {
       __int32  bodySize;
       __int32  otherStuff;
    };
    ...and then just cast that as a char* and pass that to recv
    Code:
    header myHeaderData;
    recv(sockDesc, (char*)myHeaderData, 64, 0);
    I wouldn't quote me on that, though...

    Try it and see if it works.
    I tried your way, and got...
    Code:
     error: cannot convert `buffer' from type `intheader' to type `char*'

    Quote Originally Posted by dwks
    If you casted it to anything, it would be void*, I think.
    I tried casting a void type like this...
    Code:
    void* buffer;
    numbytes=recv(sockfd, buffer, 4, 0);
    and got this...
    Code:
    error: invalid conversion from `void*' to `char*'
    It seems that type char* must be cast and it wont accept it any other way. I need a way of converting the resulting data to int. I have a vague idea that the incomming buffer is taking the binary data and reading it as ascii characters into a char type variable. If possible i'd want the data converted back to binary and represented as an int type, or just read straight into an int variable. However, most of socket programming is beyond me so I wouldnt know where to start

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Weird - sounds like a bad prototype. The Linux I have here most definitely accepts a void* parameter, but it seems like your system has a char* parameter.

    *checks*

    Hmm, seems like WinSock is this braindead culprit here. Urgh!

    If I were you, I'd get a library like ASIO or POCO that abstracts this whole mess away.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Registered User Osaou's Avatar
    Join Date
    Nov 2004
    Location
    Stockholm, Sweden
    Posts
    69
    Ugliest fella in the park, but he roars:

    Code:
    struct Header{
    	union{
    		struct{
    			__int32 size;
    			__int32 handle;
    		};
    
    		char bytes[8];
    	};
    };
    
    ...
    
    Header myHeaderData;
    recv(sockDesc, myHeaderData.bytes, sizeof(myHeaderData), 0);
    That should work?

  8. #8
    Registered User
    Join Date
    Aug 2006
    Posts
    28

    Thumbs up

    Quote Originally Posted by Osaou
    Ugliest fella in the park, but he roars:

    Code:
    struct Header{
    	union{
    		struct{
    			__int32 size;
    			__int32 handle;
    		};
    
    		char bytes[8];
    	};
    };
    
    ...
    
    Header myHeaderData;
    recv(sockDesc, myHeaderData.bytes, sizeof(myHeaderData), 0);
    That should work?
    Indeed it does, thanks
    First time i've encountered the 'union' in a stuct, but i shall keep it in mind for future reference.

    Quote Originally Posted by CornedBee
    Weird - sounds like a bad prototype. The Linux I have here most definitely accepts a void* parameter, but it seems like your system has a char* parameter.

    *checks*

    Hmm, seems like WinSock is this braindead culprit here. Urgh!

    If I were you, I'd get a library like ASIO or POCO that abstracts this whole mess away.
    Yes it is winsock. The final app will be needed in linux aswel, so I think i'll take youre advice and get one of those socket wrapper libraries.


    Thanks everyone!

  9. #9
    Registered User
    Join Date
    Aug 2006
    Posts
    28
    Quote Originally Posted by Osaou
    Ugliest fella in the park, but he roars:

    Code:
    struct Header{
    	union{
    		struct{
    			__int32 size;
    			__int32 handle;
    		};
    
    		char bytes[8];
    	};
    };
    
    ...
    
    Header myHeaderData;
    recv(sockDesc, myHeaderData.bytes, sizeof(myHeaderData), 0);
    That should work?
    Will this work both ways, i.e if i assign values to 'size' and 'handle' will 'bytes' contain the correct value?

  10. #10
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    Quote Originally Posted by megatron09
    Will this work both ways, i.e if i assign values to 'size' and 'handle' will 'bytes' contain the correct value?
    The correct binary value, not the correct ascii value. Unions are just types of data that share the same memory. When you accept data into that memory, your objects in the union are your options of how to view it. Also, you should know that the character array is just that. A character array, not a string. That is to say, if you accept two __int32, you won't be successful using any string.h functions on that character array as it likely doesn't end with a null.
    Sent from my iPadŽ

  11. #11
    Registered User
    Join Date
    Aug 2006
    Posts
    28
    Quote Originally Posted by SlyMaelstrom
    The correct binary value, not the correct ascii value. Unions are just types of data that share the same memory. When you accept data into that memory, your objects in the union are your options of how to view it. Also, you should know that the character array is just that. A character array, not a string. That is to say, if you accept two __int32, you won't be successful using any string.h functions on that character array as it likely doesn't end with a null.
    Thats ok, as long as it contains the correct binary value to send through a stream socket. It doesnt need any string methods. Thanks for clarifying that.

  12. #12
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Holy shat. Osaou, you really went MEGA overkill on that one.
    Code:
    int size;
    int handle;
    assert(sizeof(size) == 4);  //Sanity checking.
    recv(socket, (void*)&size, sizeof(size), 0);
    recv(socket, (void*)&handle, sizeof(handle), 0);
    You can typecast any address to void*. The address of size is effectively a pointer to sizeof(int), i.e. probably 4, contiguous bytes of memory. In essence, this is the same as a char* pointing at an array of 4 chars.

    Which is why the union with char[8] also worked: two 4-byte variables packed in one structure, so we have 8 contiguous bytes of memory. 'bytes', when passed to the function call, becomes an address pointing at the first of the 8 bytes of the 'char[8]', which happen to overlap with the two __int32.

    One thing though: I'm not 100% sure that the union will always work. If my memory serves correctly, the compiler may be free to optimize the structure by adding padding bits/bytes here and there to speed operations up. If padding bytes are introduced between the two __int32 in the structure, or before the first one, then the char[8] will overlap with some of the padding bytes, throwing your results off. But I'm not sure about this one, just a thought to consider.

    Another fun variation, functionally equivalent to Osaou's but without the uncertainty I mentioned:
    Code:
    unsigned char buffer[8];
    recv(socket, buffer, sizeof(buffer), 0);
    int& size = *(int*)buffer;  //or just int size
    int& handle = *(int*)&(buffer[4]);  //or just int handle
    Of course, you'll need to do a *lot* more error checking. For example, recv() isn't guaranteed to get the entire header in one go. That means you'll have to put it in a loop until all 8 bytes have been received. Fun stuff like this mean it tends to make life easier to minimize the number of recv() calls you use, by receiving large chunks of data at a time and extracting the useful data once you've finished receiving. Although, in many cases that can be overkill too.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  13. #13
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Wow Osaou, overkill.

    For a simple solution:
    Code:
    __int32 size, handle;
    recv(socket, (void*)&size, sizeof(size),0);
    recv(socket, (void*)&handle, sizeof(handle),0);
    Another solution, functionally equivalent to Osaou's:
    Code:
    unsigned char buffer[8];
    recv(socket, (void*)buffer, sizeof(buffer),0);
    __int32 size = *(__int32*)buffer;  //Or __int32& size
    __int32 handle = *(__int32*)(buffer + 4);  //Or __int32& handle
    This may look more complex than the first example, but once error checking is put in (i.e. if you don't receive the entire header in one go), the second actually becomes more elegant.

    Disclaimer about the following: Not 100% sure.
    Due to the nature of compiler optimizations and structure padding, Osaou's solution may be compromised by stray padding bits in the structure, thrown in by the compiler. This is (at least partially) why I didn't use a 'union' approach.

    I actually typed up a much more informative post, but cboard decided to eat it so I'm too lazy to go into the same detail now.

    **EDIT**
    OK wtf, cboard just vomited my other post back up. Whatever.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  14. #14
    Registered User
    Join Date
    Aug 2006
    Posts
    28
    Thanks for the info, just a few questions..

    Quote Originally Posted by Hunter2
    Holy shat. Osaou, you really went MEGA overkill on that one.
    Code:
    int size;
    int handle;
    assert(sizeof(size) == 4);  //Sanity checking.
    recv(socket, (void*)&size, sizeof(size), 0);
    recv(socket, (void*)&handle, sizeof(handle), 0);
    You can typecast any address to void*. The address of size is effectively a pointer to sizeof(int), i.e. probably 4, contiguous bytes of memory. In essence, this is the same as a char* pointing at an array of 4 chars.
    How do you mean the union is overkill? Does it need more memory or resources to work? I will probably use your suggestion regardless since you pointed out the potentialy temperamental nature of the union, but it would be interesting to know why you think this method is superior.

    Quote Originally Posted by Hunter2
    Of course, you'll need to do a *lot* more error checking. For example, recv() isn't guaranteed to get the entire header in one go. That means you'll have to put it in a loop until all 8 bytes have been received. Fun stuff like this mean it tends to make life easier to minimize the number of recv() calls you use, by receiving large chunks of data at a time and extracting the useful data once you've finished receiving. Although, in many cases that can be overkill too.
    I was thinking of doing a loop like that for the 'body' packet that follows the header (which would be easily done since the header contains the size of the body), however I didnt think an 8 byte header packet would need the same. I suppose if it makes the program more reliable then it would be a good idea.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ ini file reader problems
    By guitarist809 in forum C++ Programming
    Replies: 7
    Last Post: 09-04-2008, 06:02 AM
  2. Conversion Char To Char * Problem
    By ltanusaputra in forum Windows Programming
    Replies: 3
    Last Post: 03-01-2008, 02:06 PM
  3. code condensing
    By bcianfrocca in forum C++ Programming
    Replies: 4
    Last Post: 09-07-2005, 09:22 AM
  4. Passing structures... I can't get it right.
    By j0hnb in forum C Programming
    Replies: 6
    Last Post: 01-26-2003, 11:55 AM
  5. String sorthing, file opening and saving.
    By j0hnb in forum C Programming
    Replies: 9
    Last Post: 01-23-2003, 01:18 AM