Pointer or maths more efficient?

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
I have a project where I need to load a 32 bit variable from a byte array. I tried two different methods,
First
Code:
Sum=buff[0]+((uint32_t)buff[1]<<8)+((uint32_t)buff[2]<<16)+((uint32_t)buff[3]<<24);
And second,
Code:
  uint32_t *p=(uint32_t*)buff;                        //32 bit pointer
  Sum=*p;
I first tried this on MPLABX and, as I expected, the pointer method used 35 words less of program space.
I then tried the same thing on Arduino and to my surprise the non pointer method used 36 less program words.

I'm guessing this is to do with optimisation - the MPLABX having limited optimisation.

Is there a more efficient way to do this?

Mike.
For anyone interested, the arduino code is,
Code:
uint8_t buff[6];

void setup(){
  Serial.begin(115200);
  uint32_t Sum;
  buff[3]=0x12;
  buff[2]=0x34;
  buff[1]=0x56;
  buff[0]=0x78;
  //uint32_t *p=(uint32_t*)buff;                        //32 bit pointer
  //Sum=*p; 
  Sum=buff[0]+((uint32_t)buff[1]<<8)+((uint32_t)buff[2]<<16)+((uint32_t)buff[3]<<24);
  Serial.print("Sum = ");Serial.println(Sum,HEX);
  while(1){
  }   
}

void loop(){
}
 
The pointer method should be far faster; but that does depend on the CPU architecture and instructions available.
If it's an 8 bit CPU, it's going to be four separate byte moves anyway. A 32 bit should only need a couple of instructions.

In the 8 bit case, using a union and explicitly moving each byte directly to its destination could be the faster method?
 
Both CPUs are 8 bit which is why I was surprised that the non pointer method was quicker on the Arduino (atmega 328).
With a union I wouldn't have to do anything, I could just access it as a 32 bit word.

Mike.
 
Just did a union version and (on Arduino) takes exactly the same amount of memory as the pointer bersion.
Code:
typedef union{
  struct{
    uint32_t  i;
    uint16_t w;
  };
  struct{
    uint8_t b0;
    uint8_t b1;
    uint8_t b2;
    uint8_t b3;
    uint8_t b4;
    uint8_t b5;
  };
}buff_type;

buff_type buff;

void setup() {
  Serial.begin(115200);
  buff.b3=0x12;
  buff.b2=0x34;
  buff.b1=0x56;
  buff.b0=0x78;
  Serial.print("Sum = ");Serial.println(buff.i,HEX);
  while(1){
  }    
}

void loop() {
}
}

BTW, is there a way to have an array within a union.

Mike.
 
In the actual application the pointer can be anywhere within an 8 bit buffer - but on a 32bit boundary.

Mike.
 
I use the same method to serialise 32bit integers.

C:
union {
   unsigned long x;
   unsigned char y[4];
} buffer;
 
In the actual application the pointer can be anywhere within an 8 bit buffer - but on a 32bit boundary.
What I mean is, in your example, the 4 x 8-bit values that make up the 32-bit address, are hard coded into the source and loaded into the 4 byte buffer.

buff.b3=0x12; buff.b2=0x34; buff.b1=0x56; buff.b0=0x78;
If that is the case in the real code, then why not just assign the pointer directly ... (I'm not sure about the endianess, so this may be wrong.)

C-like:
uint32_t  i =  0x12*24 + 0x34*16 + 0x56*8 + 0x78;

The compiler should perform the math at compile time and the result shoudl be 4 byte assignments at runtime with the result be usable directly as a pointer.
 
The data is made up of 14 bit words loaded into a 56 byte buffer. 14 * 32 = 56 * 8. The 56 bytes are a 16 bit counter, a 32 bit checksum and 50 bytes of data. The checksum calculation is where the pointer/maths question comes in.

Thanks Ian, never tried putting an array in a union. Will play with it tomorrow - OMG, sounded like someone else then.

Mike.
 
Reactions: 3v0
If you enjoy hand optimizing code you may find The International Obfuscated C Code Contest interesting.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…