Different pointer types for the same address

145 views Asked by At

I am relative new to programming so I apologize if my question is basic.

Situation:

I have several float values and an array of pointers to each value. Ex:

float nr1=1.15;
float nr2=2.30; 
float nr3=23.34; 

....

float * my_address_array[3]; 

my_address_array[0] = &nr1;
my_address_array[1] = &nr2;
my_address_array[2] = &nr3;

To access one element, I can use:

float temp_value; 
float ** ptr_value; 

...

ptr_value = &my_address_array[0];

temp_value = **( ptr_value+0); // copy nr1 to temp
temp_value = **( ptr_value+1); // copy nr2 to temp
temp_value = **( ptr_value+2); // copy nr3 to temp 

So far so good. On my system float occupies 32 bits (8051 microcontroller). I need to take one float number and separate it into four 8 bit variables. Example for nr2:

My attempt was:

unsigned char storage1; 
unsigned char storage2; 
unsigned char storage3; 
unsigned char storage4; 

...

storage1 =(unsigned char) ((**( ptr_value+1)) >> 24) ;
storage2 =(unsigned char) ((**( ptr_value+1)) >> 16) ;
storage3 =(unsigned char) ((**( ptr_value+1)) >> 8) ;
storage4 =(unsigned char) ((**( ptr_value+1)) & 0xff) ;

I get bad operand type. It seems that I cannot use bit shift operations with float numbers (at least google sais that). I can add a new pointer, as in:

char ** ptr_char_value; 

...

ptr_char_value = &my_address_array[0];   // generates warning

storage1 = (*(*( ptr_char_value+1)+0));
storage2 = (*(*( ptr_char_value+1)+1));
storage3 = (*(*( ptr_char_value+1)+2));
storage4 = (*(*( ptr_char_value+1)+3));

I do get a warning (which is fair) that I am using a char type pointer for a float value. I am also not sure how reliable this is. Can anyone advise a better solution?

Thank you!

Edit: The code is for a 8051 microcontroller. I would like to make it as fast/optimal as possible.

4

There are 4 answers

3
siu On

try this. You should type cast before you can shift the data. Include stdint.h

      storage1 = (uint8_t) ((((uint32_t)**( ptr_value+1))) >> 24) & 0xFF );
5
The Paramagnetic Croissant On

Let's begin with the title:

Different pointer types for the same address

That's code smell. In C, aliasing objects through an incompatible pointer type results in undefined behavior, unless the incompatible aliasing type is (qualified or unqualified, signed or unsigned) character type.

More precisely, an object of type cv-qualified or unqualified T may only be accessed through a pointer to qualified or unqualified T. Additionally, if T is an integral type, then accessing via its (qualified or unqualified) signed or unsigned counterpart is permitted as well.

This is colloquially called the "strict aliasing rule".

Hence, you can't do

float f;
*(int *)&f

even if sizeof(float) == sizeof(int).

The possible solutions:

  1. Use memcpy(), like this (preferred):
float f = 3.14;
int i;
memcpy(&i, &f, sizeof f);
  1. Use a union (C99 only – this is UB too in C89…):
union {
    float f;
    int i;
} pun = { .f = 3.14 };
printf("%d\n", pun.i);
1
Nemanja On

Why do you want to separate float in 4 variables? That don't make any sense because of how float is represented in computer.

float in c

First bit S is sing, 0 for positive 1 for negative numbers. Then 8 bits of exponent and remaining 23 for mantissa. So, there is nothing useful you can do with 8bit parts, because they are on their own meaningless.

1
j123b567 On

with this, you are getting pointer to pointer to value

ptr_char_value = &my_address_array[0];

I don't understand how this should work.


It would be better to use pointer to float directly. Cast it to char array and get separate bytes.

char * ptr_char_value = (char *)(my_address_array[0]);
storage1 = ptr_char_value[0];
storage2 = ptr_char_value[1];
storage3 = ptr_char_value[2];
storage4 = ptr_char_value[3];

EDIT: It is also question if you realy need array of pointers to floats. It is possible to have struct, cast it to array of bytes and use these bytes directly for something.

struct my_data_type {
    float nr1;
    float nr2;
    float nr3;
}

struct my_data_type my_data;

my_data.nr1 = 1.15;
my_data.nr2 = 4.75;
my_data.nr3 = 8.95;

char * ptr_char_value = (char *)&my_data;

// nr1
storage1 = ptr_char_value[0];
...

// nr2
storage5 = ptr_char_value[4];
...

// nr3
storage9 = ptr_char_value[8];
...