Jump to content
43oh

Casting problems: extract 4 bytes from a long int.


Recommended Posts

Hi,

 

I'm new to this platform, I love it, it's cheap and powerful enough for my needs. I'm also trying to improve my C knowledge, I've using PicBasic a lot and I'm much more familiar with it :smile:

 

I'm trying to assign the 4 bytes of a long int to 4 different variables. I've been looking on the Internet for a solution and apparently I found it. Here's the code that SHOULD  work:


byte aa,bb,cc,dd;
long int cast = 0xAABBCCDD;

void loop(){
  aa = (byte) cast >> 24;
  bb = (byte) cast >> 16;
  cc = (byte) cast >> 8;
  dd = (byte) cast;

  Serial.print("cast= ");
  Serial.print(cast, HEX);
  Serial.print("   a=");
  Serial.print(aa, HEX);
  Serial.print("   b=");
  Serial.print(bb, HEX);
  Serial.print(" c=");
  Serial.print(cc, HEX);
  Serial.print("   d=");
  Serial.print(dd, HEX);
}



What I get on the serial monitor(I'm using an MSP430g2553 to have Hardware UART) is this:

cast= AABBCCDD   a=0   b=0 c=0   d=DD

 

Where am I wrong?

Link to post
Share on other sites

I'm not familiar enough with C, but I think the "(byte) cast", just casts "cast" before shifting, hence only the last bytes shows., i.e. your code is equivalent to

  aa = 0xDD >> 24;
  bb = 0xDD >> 16;
  cc = 0xDD >> 8;
  dd = 0xDD cast;
Maybe you could try
  aa = (byte) (cast >> 24);
  bb = (byte) (cast >> 16);
  cc = (byte) (cast >> 8);
  dd = (byte) cast;

note the extra parenthesis.

 

Edit: oPossum beat me, but I don't like the last solution since it's not portable.

Aren't there standard functions/macros that do this taking care of the endianness of the target system?

Link to post
Share on other sites

 

aa = (byte) (cast >> 24);
bb = (byte) (cast >> 16);
cc = (byte) (cast >> 8);
dd = (byte) cast;

faster code:

byte *p = (byte *)&cast;
dd = *p++;
cc = *p++;
bb = *p++;
aa = *p;
The second code may be a little faster, but it is less portable: you assume that the least significant byte is at the first memory location, this may be true for the msp430, but you cannot relyon this being the case on any other platform. I suggest you use the first code over the second one.
Link to post
Share on other sites

Neither method is portable - they both rely upon undefined behavior of the C compiler. As a practical matter they are equally portable. The only popular big endian microcontoller was the M68k series, and it is essentially dead.

 

If you think there is a small difference in code size and speed - just look at the asm code generated by the compiler...

Link to post
Share on other sites

Not ideal.  Don't assume you know how big int, short, and long are.  I know there's a tendency in the microcontroller world to use long as if it were mandated to be 32 bits and short as mandated to be 16 bits, but it just ain't so.  Also, try to avoid signed integers when you're extracting bits from a multi-octet integral type: sign preservation in right shifts may be costly and can bleed into the output if you don't remember to mask off the upper bits.

#include <stdint.h>
union breakdown32_t  {
  uint32_t d32[1];
  uint16_t d16[2];
  uint8_t d8[4];
};
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...