• Advertisement
Sign in to follow this  

hi and lo byte

This topic is 4648 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hello, how can i save two values in one variable? i think this shoudl be possible to set the hi byte and the lo byte in a 16 bit integer, right? how can i set the hi and lo byte? thanks!

Share this post


Link to post
Share on other sites
Advertisement
Well, if you want to pack 2 bytes into a 16 bit short, you could do it like this:
unsigned short Value = HI << 8 + LO;

It's a simple matter of shifting up the higher bytes to the right places. To get the values back:
unsigned char LO = Value & 0xff; unsigned char HI = (Value & 0xff00) >> 8;

I'd question whether this is a good idea, but I can't really say without knowing what you're trying to do.

Share this post


Link to post
Share on other sites
thank you!
yes its an unsigned short (UInt16).

i think that's exactly what i need.

another question:
does something like this

x & 0xff

perform a modulo 255 operation to x?
if yes, than what is the difference to just writing x % 255 ?

thank you!

Share this post


Link to post
Share on other sites

unsigned short Pack(unsigned char high, unsigned char low) {
return ((high << 8) + low);
}
unsigned char UnpackLow( unsigned short value ) {
return (value & 0xFF);
}
unsigned char UnpackHigh( unsigned short value ) {
return ((value & 0xFF00) >> 8);
}


edit: bah, Promit posted while I was writing :(

Share this post


Link to post
Share on other sites
Quote:

x & 0xff

perform a modulo 255 operation to x?
if yes, than what is the difference to just writing x % 255 ?


& and % are two very different things. & is the logical AND operation(| is OR).

AND works like this:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

so if x = 1011001100011101 and you wanted the low byte:

1011001100011101
0000000011111111 (& 0xFF)
----------------
0000000000011101 = Low byte(top 8 bits will always be 0)

so if x = 1011001100011101 and you wanted the high byte:

1011001100011101
1111111100000000 (& 0xFF00)
----------------
1011001100000000 = Shift over 8 bits and get the high byte

Edit: haha nice try _DarkWIng_

Share this post


Link to post
Share on other sites
Quote:
Original post by ehmdjii
does something like this

x & 0xff

perform a modulo 255 operation to x?
if yes, than what is the difference to just writing x % 255 ?

This is bitwise and. It performs and on each bit and it basically one of the atomic operations of CPU.


A B | A&B
----+----
0 0 | 0
0 1 | 0
1 0 | 0
1 1 | 1


ps: to late.. AGAIN!

Share this post


Link to post
Share on other sites
After some testing it seems theres no need it use & to get the high byte, just shifting will work.

unsigned char UnpackHigh( unsigned short value ) {
return (value>>8);
}

or

unsigned char HI = (Value >> 8);

This is probably because C++ uses shift, not rotate.

Share this post


Link to post
Share on other sites
ah, i think i got it!

thanks guys!

so with something like

unsigned short value = ( (shortA & 0xff) << 8) | (shortB & 0xff);

i can write shortA and shortB in the hi and lo byte of value?
(they are both positive)

Share this post


Link to post
Share on other sites
Well you can't store two shorts in one and having two seperate shorts just to store one byte each is kind of silly unless you need to test for overflows on math operations(ex. writing an emulator).

Use Darkwing's function too pack two bytes into one short:

unsigned short Pack(unsigned char high, unsigned char low) {
return ((high << 8) | low);
}

unsigned short Value=Pack(0x65,0xF3); //Value=0x65F3

(| is faster than +)

Share this post


Link to post
Share on other sites
Then of course there exists the ugly, but slightly faster version which takes advantage of the addressing:


unsigned char a,b;
unsigned short c;
/* --- variable setup here --- */

*((unsigned char *)&c) = b;
*(((unsigned char *)&c)+1) = a;



It turns out to be aproximately 20% faster (ie. takes 20% less time to execute) when tested with a loop construct on a Athlon when compiled with gcc 3. Of course simple loop-test doesn't tell the whole truth and obviously this kind of micro-optimization is next to pointless. :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Scet
After some testing it seems theres no need it use & to get the high byte, just shifting will work.


Not a good idea. The size of your data types (e.g. short) is not specified completely by the specification. IIRC, the standard specifies that short is *at least* 16 bits - but it may be more. Depending on your implementation, this could have unforseen side-effects.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by Scet
After some testing it seems theres no need it use & to get the high byte, just shifting will work.


Not a good idea. The size of your data types (e.g. short) is not specified completely by the specification. IIRC, the standard specifies that short is *at least* 16 bits - but it may be more. Depending on your implementation, this could have unforseen side-effects.


Yes if a short was more than 16 bits it wouldn't work, however it wouldn't work with 0xFF00 either so you don't have much of a point. You would have to adjust both on a different platform so just stick with shifting.

Share this post


Link to post
Share on other sites
A less confusing alternative to Winograd's code (hopefully):


unsigned char a,b;
unsigned short c;
/* --- variable setup here --- */

((unsigned char *)&c)[0] = b;
((unsigned char *)&c)[1] = a;




[EDIT]
I've gotta learn to stop rewording my sentences without checking them...

Share this post


Link to post
Share on other sites
Or, to be (mostly) correct C++:
template <typename BaseType>
unsigned char &IndexBytes(BaseType &p_Type, const size_t p_WhichByte)
{
if(p_WhichByte >= sizeof(BaseType))
{
throw /*Some Exception*/;
}
return reinterpret_cast<unsigned char *>(&p_Type)[p_WhichByte];
}

Share this post


Link to post
Share on other sites
Quote:
Original post by _DarkWIng_

unsigned short Pack(unsigned char high, unsigned char low) {
return ((high << 8) + low);
}
unsigned char UnpackLow( unsigned short value ) {
return (value & 0xFF);
}
unsigned char UnpackHigh( unsigned short value ) {
return ((value & 0xFF00) >> 8);
}


edit: bah, Promit posted while I was writing :(
Just a little mirco-optimisation tip:
Do the right shift before the and. That way the compiled code doesn't have to store such large constants. Get into the habbit of doing it like this
unsigned char UnpackHigh( unsigned short value ) {
return ((value >> 8) & 0xFF);
}
It may even still have the 0xFF in a register from the previous and instruction.
Sure many would say that this is pointless micro-optimisation. Yeah well it's always a win so ya may as well just do it that way every time to begin with. After all, it could make a significant difference if you do this in an inner loop.[smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by Winograd
Then of course there exists the ugly, but slightly faster version which takes advantage of the addressing:

*** Source Snippet Removed ***

That's a memory corruption bug waiting to happen. There is no guarantee that independent automatic variables will be layed out next to each other. Hell, by the time the optimizer gets done with them they may not even exist anymore. Please *do not* do that.

If you want to do this sort of thing without all the bit-twiddling then define a struct containing your indivisual bytes. If you then want to access the all the bytes in one go you can wrap the whole thing in a union.

Share this post


Link to post
Share on other sites
Quote:
Original post by ehmdjii
another question:
does something like this

x & 0xff

perform a modulo 255 operation to x?
if yes, than what is the difference to just writing x % 255 ?

thank you!


It does not perform modulo 255 but modulo 256. x & 0xFF takes lowest 8 bits of number so the biggest result is 255, not 254 as would be with x % 255.
So it is the same as x % 256.
You can use this "trick" to get modulo for every power of 2, it won't work for other numbers.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
ok there is an infinetely simple solution to your problem

union {

int a;
char b[2]

} single;


single.a = 32;

OR

single.b[0]=1;
single.b[1]=2;


sine this is a union, therefore ALL member variables of the union share the same memory space... which means that int a takes up 2 bytes in memory, which the character array takes up the same 2 byte... i hope u know what unions are


|---- 1 byte ----||---- 1 byte ----|
|------------ 2 bytes -------------|

|------------ int a -------------|
|---- char b[1]--||--- char b[0] --|

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
union {

int a;
char b[2]

} single;

is wrong ...int is not necessarily a 2byte word ... in fact most compilers these days will treat it as a 4-byte word. and you didn;t even make it unsigned ...tut-tut.

union {

unsigned short a;
unsigned char b[2]

} single;

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Anonymous Poster
ok there is an infinetely simple solution to your problem

union {

int a;
char b[2]

} single;




Wouldn't there be big/little endian concerns here?

Share this post


Link to post
Share on other sites
Quote:
Original post by Anon Mike
Quote:
Original post by Winograd
Then of course there exists the ugly, but slightly faster version which takes advantage of the addressing:

*** Source Snippet Removed ***

There is no guarantee that independent automatic variables will be layed out next to each other.


That's one weird compiler if unsigned short is not a contiguous and as far as I see that's the only thing that snippet relies on. If a take the "base" address of a short, I will get exactly that. Now if I increase the address by one I'll get the address right next to it, right? Only automatic variables are the variables which store the pointer values and I couldn't care less if they are not packed together.

The union thingy is neat trick and looks cleaner in use. Altough I fail to see why it would be any safer..

Quote:
Original post by Anon Mike
Please *do not* do that.


I agree, don't use unnecessary pointer tricks :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by Anonymous Poster
ok there is an infinetely simple solution to your problem

union {

int a;
char b[2]

} single;




Wouldn't there be big/little endian concerns here?


Yes. The result will be different on systems with different endians.

Share this post


Link to post
Share on other sites
Quote:
Original post by Winograd
That's one weird compiler if unsigned short is not a contiguous and as far as I see that's the only thing that snippet relies on.


Whoops, my bad. It looked at first like you were doing something like:


// two bytes on the stack
unsigned char a, b;
// treat them as a 16-bit value
* (short *) &a = 0;


Which is really evil but occasionally works. Yes I've seen people do that!

Share this post


Link to post
Share on other sites
You should by preference use the bitshiftint, anding, & oring method to pack bytes into a short for at least two reasons:
It works the same on different endian machines making your code be able to more easily be ported to another platform and maintain the ability to send stuff easily between them for example.
The memory writes will be half as many, a single short (or int if you're doing the same with ints) and not of two seperate writes to single bytes in memory. Surely it would be faster to do fewer (but larger) writes if you're doing a huge number of these?

Share this post


Link to post
Share on other sites
Quote:
Original post by Anon Mike
Quote:
Original post by Winograd
That's one weird compiler if unsigned short is not a contiguous and as far as I see that's the only thing that snippet relies on.


Whoops, my bad. It looked at first like you were doing something like:


// two bytes on the stack
unsigned char a, b;
// treat them as a 16-bit value
* (short *) &a = 0;


Which is really evil but occasionally works. Yes I've seen people do that!



I'm not sure if that works at all. IIRC, most compiler will inflate char variables ON THE STACK to make them as large as whatever the machine word size is on that particular architecture, so as to properly align them in memory and speed up access to variables on the stack. Thus on most systems a and b would really take up 4 bytes each and your second line wouldn't affect the value of b at all.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement