Thread: Getting a 2 byte number from an array of char's

  1. #1
    Registered User
    Join Date
    May 2004
    Posts
    114

    Question Getting a 2 byte number from an array of char's

    I need to take numbers from an array of char's. They are two bytes long. I have managed to do it but it looks really messy.

    Of course the example doesn't show the bit which fills header, but its not empty.

    Code:
        int bob;
        char header[200];
    
        bob = *((unsigned short int*)(header + 15));
        printf("Test: %d\n",bob);
    Could you tell me if this is the best way of doing it or if theres a more readable way? Thanks
    Last edited by kzar; 04-09-2005 at 11:06 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > Could you tell me if this is the best way of doing it
    It's a pretty poor way actually.
    1. It assumes that the endian the machine you're using is the same as the endian of the machine which generated the data.
    2. Your cast changes the alignment of a data type (namely short) to something which could be an invalid address for a short. On some machines which don't allow mis-aligned data access, you get a bus error.

    Code:
    bob = ((unsigned short)header[15]) * 256 + header[16];
    So long as you make sure you know the endian of the data stored in the buffer, it is independent of the endian of your local machine (and no pesky bus errors either)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2004
    Posts
    114
    Code:
    bob = ((unsigned short)header[15]) * 256 + header[16];
    The data at header[15] to header[16] is 100 but that code gives me 25600. The old code is still giving 100 so I know the array is still ok.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    So its
    header[15] + header[16] * 256;

    I did say "So long as you make sure you know the endian of the data stored in the buffer"
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    May 2004
    Posts
    114
    Quote Originally Posted by Salem
    So its
    header[15] + header[16] * 256;

    I did say "So long as you make sure you know the endian of the data stored in the buffer"
    Sorry if I'm honest I don't even know what an endian is. Your right though that code works great.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    I bet google does...
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    May 2004
    Posts
    114
    Quote Originally Posted by Salem
    I bet google does...
    Yea of course, I'm not asking for a definition, I was just explaining why I hadn't picked up the problem. Thanks for the help

  8. #8
    Registered User samGwilliam's Avatar
    Join Date
    Feb 2002
    Location
    Newport
    Posts
    382
    Code:
    #include <iostream.h>
    
    #define SIZE 10
    
    int main (void)
    {
    	unsigned short word [SIZE];
    	unsigned char *byte;
    
    	byte = (unsigned char *) word;
    
    	byte [0] = 1;
    	byte [1] = 1;
    
    	cout << word [0];
    }
    That seems to do the trick (kind of like your way). The pointer cast allows one to view the same memory space from two different viewpoints (as bytes or words). Byte 0 and 1 are 00000001 therefore word 0 is 0000000100000001 (257).

    Or you could do:

    Code:
    #include <iostream.h>
    
    #define SIZE 10
    
    union u
    {
    	unsigned short word [SIZE];
    	unsigned char byte [SIZE * sizeof (short)];
    };
    
    int main (void)
    {
    	u un;
    
    	un.byte [0] = 1;
    	un.byte [1] = 1;
    
    	cout << un.word [0];
    }
    Which achieves pretty much the same thing. Whichever you think is neater.
    Last edited by samGwilliam; 04-09-2005 at 01:07 PM.
    Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)

  9. #9
    Registered User
    Join Date
    May 2004
    Posts
    114
    Quote Originally Posted by samGwilliam
    Code:
    #include <iostream.h>
    
    #define SIZE 10
    
    int main (void)
    {
    	unsigned short word [SIZE];
    	unsigned char *byte;
    
    	byte = (unsigned char *) word;
    
    	byte [0] = 1;
    	byte [1] = 1;
    
    	cout << word [0];
    }
    That seems to do the trick (kind of like your way). The pointer cast allows one to view the same memory space from two different viewpoints (as bytes or words). Byte 0 and 1 are 00000001 therefore word 0 is 0000000100000001 (257).

    Or you could do:

    Code:
    #include <iostream.h>
    
    #define SIZE 10
    
    union u
    {
    	unsigned short word [SIZE];
    	unsigned char byte [SIZE * sizeof (short)];
    };
    
    int main (void)
    {
    	u un;
    
    	un.byte [0] = 1;
    	un.byte [1] = 1;
    
    	cout << un.word [0];
    }
    Which achieves pretty much the same thing. Whichever you think is neater.

    I'm going to use the "(unsigned short)header[27] + header[28] * 256;" type way because I need to do about 20 in a row and it takes too much space otherwise!

  10. #10
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    another way to do it would be.

    Code:
    #include <stdio.h>
    #include <netinet/in.h>
    
    int main()
    {
    unsigned short int bob;
    unsigned char header[200];
    
    header[15] = 10;
    header[16] = 9;
    
    printf("header[15]= %d header[16] = %d\n",header[15],header[16]);
    
    bob = htons(header[15]);              					 /* MSB */
    bob = bob | (0xFFFF & htons(header[16])) >> 8;           /* LSB */
    
    printf ("bob: HEX = 0x%4X DEC = %d\n", bob,bob);
    
    return 0;
    }
    Program Output:
    header[15]= 10 header[16] = 9
    bob: HEX = 0x A09 DEC = 2569

  11. #11
    Registered User samGwilliam's Avatar
    Join Date
    Feb 2002
    Location
    Newport
    Posts
    382
    Why are you &ing something with 0xFFFF? What does it achieve?
    Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)

  12. #12
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Hi samGwilliam.

    You are right. "&" ing didint acheieve anything. Alternatively, you can achieve the same results without using htons() as follows.

    Code:
    bob = header[15] << 8 | header[16] ;
    Above hold true assuming data is sent over the network, in which case its supposed to be in Network byte order (MSB first).

    program Output:
    $ ./bit1.exe
    header[15]= 255 header[16] = 210
    bob: HEX = 0xFFD2 DEC = 65490

  13. #13
    The C-er
    Join Date
    Mar 2004
    Posts
    192
    Here's a line from my life program.

    Code:
    *(unsigned int*)&this->cells[2*row-1][cellcol] += mod0;
    I'm doing it the "pretty poor" way - but non-portability is a given in this app.

    I like the idea with unions, I had considered doing it that way, and I still might.

  14. #14
    Registered User samGwilliam's Avatar
    Join Date
    Feb 2002
    Location
    Newport
    Posts
    382
    This thread gave me an idea for writing an endian tester:

    Code:
    #include <iostream.h>
    
    union wd
    {
    	unsigned short word [1];
    	unsigned char byte [sizeof (short)];
    };
    
    int main (void)
    {	
    	wd w;
    
    	w.byte [0] = 1;
    	w.byte [1] = 2;
    
    	cout << "This machine is ";
    
    	if (w.word [0] == 513)
    		cout << "little-endian." << endl;
    
    	else if (w.word [0] == 258)
    		cout << "big-endian." << endl;
    
    	else
    		cout << "screwed up." << endl;
    }
    Again, I use the union method because I find it elegant.
    Last edited by samGwilliam; 04-10-2005 at 05:23 PM.
    Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You do know that there's absolutely no point in declaring an array with a size of one, right? ... No apprently you don't.

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. brace-enclosed error
    By jdc18 in forum C++ Programming
    Replies: 53
    Last Post: 05-03-2007, 05:49 PM
  2. question about multidimensional arrays
    By richdb in forum C Programming
    Replies: 22
    Last Post: 02-26-2006, 09:51 AM
  3. Class Template Trouble
    By pliang in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 04:15 AM
  4. help with a source code..
    By venom424 in forum C++ Programming
    Replies: 8
    Last Post: 05-21-2004, 12:42 PM
  5. error: identifier "byte" is undefined.
    By Hulag in forum C++ Programming
    Replies: 4
    Last Post: 12-10-2003, 05:46 PM