0
void OPC_N2_data_read()
{
    unsigned int32 iobyte[3][4] = {0x00, };
    int32 PM_int[3] = {0x00, };
    float PM[3] = {0x00, };

    int8 i,j,k;
    int8 mask = 0x80;
    const int16 mask1 = 0x0001;
    const int16 mask0 = 0x0000;
    int8 trash_byte = 0x32;

    output_bit(ss,1);
    output_bit(PM_CLOCK_pin,0);
    delay_us (1);
    output_bit(ss,0);
    delay_us (2);  
    for( i = 0 ; i < 3 ; i ++ )
    {
      for ( j = 0 ; j < 4 ; j ++ )
      {
         for (k = 0 ; k < 8 ; k ++ )
         {
            output_bit(PM_CLOCK_pin,1); 
            iobyte[i][j] = iobyte[i][j] << 1;           
            if ( input ( PM_MISO_pin))
            {
               iobyte[i][j] |= mask1;
            }
            else
            {
               iobyte[i][j] |= mask0;
            }
            if ((trash_byte & mask) >0)
            {
                output_high(PM_MOSI_pin);
            }
            else
            {
               output_bit(PM_MOSI_pin,0);
            }            
            delay_us(1);                             
            output_bit(PM_CLOCK_pin,0);            
            delay_us(5); 
            mask = mask >>1;
         }
      }
   }
   delay_us(3);
   output_high(ss);

   for(i = 0; i<3; i++)
   {
     PM_int[i] = ((iobyte[i][0]<<24)|(iobyte[i][1]<<16)|(iobyte[i][2]<<8)|(iobyte[i][3]));
     PM[i] = *(float*)&PM_int;

   }   
   printf ("%x%x%x%x\r\n",iobyte[0][0],iobyte[0][1],iobyte[0][2],iobyte[0][3]);
   printf ("%x%x%x%x\r\n",iobyte[1][0],iobyte[1][1],iobyte[1][2],iobyte[1][3]);
   printf ("%x%x%x%x\r\n",iobyte[2][0],iobyte[2][1],iobyte[2][2],iobyte[2][3]);
   printf ("%lx,%lx,%lx\r\n", PM_int[0],PM_int[1],PM_int[2]);
   printf ("%3.5f,%3.5f,%3.5f\r\n", PM[0],PM[1],PM[2]);

}

I receive data from a 4-byte array. This data is a float value. I check through the computer, I see the following.

e911bd41 d867e641 8084e941 e911bd41,d867e641,8084e941 0.00000,0.00000,0.00000

Making the four data into one INT value works fine. PM_int[0],PM_int[1],PM_int[2]

However, if you try to convert this to a float value, only 0.00000 is displayed.

I do not know where the problem is.

Vinay Shukla
  • 1,818
  • 13
  • 41
  • `PM[i] = *(float*)&PM_int;` breaks strict aliasing rules. Use `memcpy` instead. – user694733 Nov 11 '16 at 12:11
  • 2
    @user694733: `memcpy` breaks them, too. The only fully legal way for type-punning is a `union`. Nevertheless, OP should use proper (de) serialisation using bitshifts and masking to an `uint32_t` and then use a `union`. – too honest for this site Nov 11 '16 at 12:15
  • 1
    1) Don't use signed integers for bitshifts. Certain values will invoke undefined behaviour, for others the result is implementation defined. 2) Use standard types for fixed-width type, no homebrew stuff! See `stdint.h` – too honest for this site Nov 11 '16 at 12:18
  • @Olaf Citation from the standard please. `memcpy` is a copy operation. There is no reason why it would break the rule. – user694733 Nov 11 '16 at 12:19
  • @user694733: 6.5p6: "The effective type of an object for an access to its stored value is the declared type of the object, if any." - Both objects **have** a declared type. There is an explicity exception for punning through a `union`, though. `memcpy` has the semantics of an assignment operator here. – too honest for this site Nov 11 '16 at 12:20
  • 1
    @Olaf `memcpy` works in terms of a character type. 7.24.2.1 p2: *"The memcpy function copies n **characters** from the object pointed to by s2 into the object pointed to by s1."* Converting any data pointer type to `char*` is well defined. Rule you have given applies for accessing **same** object through different type. – user694733 Nov 11 '16 at 12:25
  • @user694733: The description of a library function does not break the rules of the language itself! This violates the efffective type rule which is one of the most important (and least understood) constraint in C. There have been already long discussions about all this; do some research, Comments are neither the place nor is this the time for a discussion. Just that: The fact that it worked **for your** does not mean does **not** invoke UB! – too honest for this site Nov 11 '16 at 12:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/127893/discussion-between-user694733-and-olaf). – user694733 Nov 11 '16 at 12:38
  • 1
    @Olaf it is well understood that a `memcpy` from one variable to another with different type is perfectly legal. Your assertion that "memcpy has the semantics of an assignment operator here" is unjustifiable. In all other respects `memcpy` behaves as if it copies via `char *`, and this is implied to some degree by the definition of the function. You surely recognize that a copy via a `char *` is legal (it is mandated so in 6.5), to suggest that an equivalent `memcpy` behaves differently is untenable. I see no justification for assuming `memcpy` causes an access via any other type than `char`. – davmac Nov 11 '16 at 14:11
  • 1
    Furthermore telling @user694733 to "do some research" is ridiculous, seeing as nearly all complete discussions of the topic mention the legality of using `memcpy`. For example, http://dbp-consulting.com/tutorials/StrictAliasing.html ; the accepted answer on http://stackoverflow.com/questions/3275353/c-aliasing-rules-and-memcpy ; http://blog.regehr.org/archives/1307 ("it is always OK to inspect an object’s representation via an array of chars. This is necessary to make memcpy-like functions work properly"). – davmac Nov 11 '16 at 14:41
  • the posted code does not compile. To start with, it is missing the needed `#include` statements. – user3629249 Nov 12 '16 at 19:09
  • this type: `unsigned int32` (and similar types) are not part of the C language. If you were to `#include ` then you could use types like: `uint32_t` – user3629249 Nov 12 '16 at 19:11
  • when initializing float variables, use float literals, not integer literals. a float literal looks similar to `0,0f` – user3629249 Nov 12 '16 at 19:14
  • the posted code contains several 'magic' numbers. 'magic' numbers are numbers with no basis. I.E. 3, 4, 8 Suggest using an `enum` statement or `#define` statements to give those 'magic' numbers meaningful names, then use those meaningful names throughout the code – user3629249 Nov 12 '16 at 19:18
  • this line: `iobyte[i][j] |= mask0;` has no effect because `mask0` is a 0 – user3629249 Nov 12 '16 at 19:21

1 Answers1

0

Looking on your source code shows that you are assuming that the received iobyte[i][0] to iobyte[i][3] shall be assumed as a float when ordering in big-endian format:

PM_int[i] = ((iobyte[i][0]<<24)|(iobyte[i][1]<<16)|(iobyte[i][2]<<8)|(iobyte[i][3]));

But if you want to convert correctly a 32bits floating-point value, you have to know if the source CPU and the destination CPU are both big-endian or little-endian. Otherwise, it is necessary to reverse the byte order before trying to convert values. So, if your target has a different endianness, replace the above code by the following:

PM_int[i] = ((iobyte[i][3]<<24)|(iobyte[i][2]<<16)|(iobyte[i][1]<<8)|(iobyte[i][0]));

In your source code, an error of the cast formatting between the float PM[i] and the 32bits integer PM_int[i] compute a bad result. The cast must be performed to the good element of the array PM_int[i].

PM[i] = *((float*)&(PM_int[i]));

Instead of:

PM[i] = *(float*)&PM_int;

With the 3 received float values {0xe9, 0x11, 0xbd, 0x41 }, {0xd8, 0x67, 0xe6, 0x41 }, {0x80, 0x84, 0xe9, 0x41 }, the output becomes:

e911bd41
d867e641
8084e941
41bd11e9,41e667d8,41e98480
23.63375,28.80070,29.18970
J. Piquard
  • 1,665
  • 2
  • 12
  • 17