-3

I have the following codes:


#include "stdio.h"
#include "stdint.h"
#include <string>
#include "string.h"
#include<iostream>
using namespace std;

class myMessage
{
public:
    uint8_t latitude[4];                  //Binary
    uint8_t longitude[4];                 //Binary
};



int8_t sentMessage[4]={0,};

int main()
{
    myMessage msg;
    memset(&msg, 0x00, sizeof(msg));

    uint8_t Input_Latitude[4] = {0x4,0x82,0x85,0xf1} ;

    printf("%x ", Input_Latitude[0] );
    printf("%x ", Input_Latitude[1] );
    printf("%x ", Input_Latitude[2] );
    printf("%x \n", Input_Latitude[3] );
    memcpy(&msg.latitude[0], &Input_Latitude, sizeof(uint8_t) * 4);

    printf("%x ", msg.latitude[0] );
    printf("%x ", msg.latitude[1] );
    printf("%x ", msg.latitude[2] );
    printf("%x \n", msg.latitude[3] );

    memcpy(&sentMessage[0], &msg.latitude[0], 4);
    printf("%02X ", sentMessage[0] );
    printf("%02X ", sentMessage[1] );

    printf("%02X ", sentMessage[2] );
    printf("%02X \n", sentMessage[3] );
}

When I print it out, I have: 4 82 85 f1 ==> original value

4 82 85 f1 ==> copy from unsign int to unsign int

04 FFFFFF82 FFFFFF85 FFFFFFF1 ==> after implicit converting from unsign int to int and printf

Why do we have a bunch of FFFFFFF ????

I understand that there is some implicit conversion from uint8 to int8 when I run

memcpy(&sentMessage[0], &msg.latitude[0], 4);
// sentMessage is int8_t
// msg.latitude[0] is uint8_t

However, I what I don't understand is some extra FFFFF that clearly exceeds the size of each element in array sentMessage[]

Minh Pham
  • 275
  • 1
  • 13
  • 1
    Because that's how two's-complement arithmetic works? – Sam Varshavchik Dec 06 '21 at 11:54
  • 1
    The undefined behaviour is caused by mismatch of format specifier with the corresponding argument. `%x` tells `printf()` to ASSUME the corresponding argument is of type `unsigned`. You are supplying values of type `uint8_t` and `int8_t`, neither of which are `unsigned`. If you want to use the `%x` format with such types, explicitly convert them to `unsigned` e.g. `printf("%x ", unsigned(Input_Latitude[0]));`. Note - although `uint8_t` is a unsigned type, it is not the same type as `unsigned`. – Peter Dec 06 '21 at 11:59
  • Isn't C-elipsis already promote type shorter than `int` as `int`... – Jarod42 Dec 06 '21 at 12:10
  • @Peter: There would be some kind of implicit conversion from uinit8 to init8 when I run memcpy(&sentMessage[0], &msg.latitude[0], 4) that causes unexpected behavior. What I don't get is how they print out some extra FFFFFFF, which I think exceed the allowed size of each element of sentMessage[] array – Minh Pham Dec 06 '21 at 12:18
  • `uint8_t Input_Latitude[4] = {0x4,0x82,0x85,0xf1} ;` some of these values are larger than an `int8_t` can hold. So what happens when you copy them into one? – BoP Dec 06 '21 at 12:20
  • @Minh - There is no conversion in `memcpy`, it just copies the bits. – BoP Dec 06 '21 at 12:21
  • why is 0xf1 could be larger thatn unit8_t ? it is basically 8 bits, 2 bytes: FFFF 0001 !!! – Minh Pham Dec 06 '21 at 12:22
  • 1
    No, 8 bits is not 2 bytes. Each byte is (at least) 8 bits, But `unsigned` is a larger type than `uint8_t` and you have TOLD `printf()` to ASSUME it is passed an `unsigned` - which is typically represented by two or more bytes. When you pass a function an 8-bit value but it has been told to assume a 16-bit value is passed, it is (with your compile/library) somehow accessing 16 bits and using them to produce output. The behaviour is undefined, because the standard doesn't mandate what happens. – Peter Dec 06 '21 at 12:34
  • @Peter: agree. I have TOLD printf() to assume it passed an unsigned int ! This question has the same answer to : https://stackoverflow.com/questions/3555791/why-does-printf-not-print-out-just-one-byte-when-printing-hex – Minh Pham Dec 06 '21 at 12:46

2 Answers2

1

While changing the Printf will work it's not the root cause of the issue.

When you define your array

int8_t sentMessage[4]={0,};

You are using type of int8_t instead of uint8_t so printf tries to print an unsigned integer as a signed integer. The reason you see a bunch of F's is the internal storage method, you can see more about this concept here

Nick Gkloumpos
  • 121
  • 3
  • 8
  • 1
    Because 0x82 has the left most digit in range of 8 -> F, compiler assumes that it is a negative value. Printf only prints a bunch of FFFFF because %X because it assumes X as int , 8 bytes. If I use a different format specifier, it would print out correctly. There is not implicit conversion between unsigned to sign values, nor is any 2's complement operation done – Minh Pham Dec 07 '21 at 11:59
0

The program prints out FFFFFF82 with some extra Fs because of printf.

Printf takes %x and assume that I will pass into it value unsigned int which has 8 bytes.

0x82 with int8_t is unsign 8 bits, or 1 byte. Since printf assumes it is unsigned int, 8 bytes, it prints extra FFFFFF82.

To fix it, we can use format specifier %#04hhx.

The answer to this question is same as Why does printf not print out just one byte when printing hex?

printf("%#04hhx ", sentMessage[0] );
E_net4
  • 27,810
  • 13
  • 101
  • 139
Minh Pham
  • 275
  • 1
  • 13