Home > Net >  Why does char 0x0 becomes 0xFF (255) in QT C QByteArray?
Why does char 0x0 becomes 0xFF (255) in QT C QByteArray?

Time:03-20

Via the USB, I send the following to my QT C application. As you can see, we are sending total 5 bytes of data to my QT C application.

/* Create array of prescalers */
uint8_t send_data_array[5] = {0};
uint8_t index = 0;

/* Fill the array */
send_data_array[index  ] = SEND_BACK_PWM_PRESCALERS_MESSAGE_TYPE;
send_data_array[index  ] = STM32_PLC_PWM0_To_PWM3_Get_Prescaler() >> 8;
send_data_array[index  ] = STM32_PLC_PWM0_To_PWM3_Get_Prescaler();
send_data_array[index  ] = STM32_PLC_PWM4_To_PWM7_Get_Prescaler() >> 8;
send_data_array[index  ] = STM32_PLC_PWM4_To_PWM7_Get_Prescaler();

/* Send the data via USB */
CDC_Transmit_FS(send_data_array, index);

When I send data, it looks like this:

enter image description here

So when I recieve the data in my QT C application, it looks like this:

uint32_t MessageServiceThread::readPWMPrescalersFromSTM32PLC(QByteArray usbDataRaw, uint32_t byteIndex){
    pwmPrescaler[0] = (usbDataRaw.at(byteIndex) << 8) | usbDataRaw.at(byteIndex   1);
    byteIndex  = 2;
    pwmPrescaler[1] = (usbDataRaw.at(byteIndex) << 8) | usbDataRaw.at(byteIndex   1);
    byteIndex  = 2;
    uint16_t p0 =  pwmPrescaler[0];
    uint16_t p1 =  pwmPrescaler[1];

Where usbDataRaw contains the data. The first index of usbDataRaw contains the message type that describe what type of message it is. So the code above begins from index 1, not index 0.

Let's focusing on

 pwmPrescaler[0] = (usbDataRaw.at(byteIndex) << 8) | usbDataRaw.at(byteIndex   1);

Here pwmPrescaler is declared as uint16_t pwmPrescaler[2]; and usbDataRaw.at(byteIndex) = 0 and usbDataRaw.at(byteIndex 1) = 250.

But when I combinde them as you can see, I get the number 65530!

enter image description here

That's funny, because -6/250 is 0xFA or 250. That means that a 0 must have to become 0xFF right? Why else does 250 become 65530?

enter image description here

CodePudding user response:

It is unspecified whether char is signed or unsigned.

usbDataRaw.at(byteIndex 1) results in a char that intends stores the value 250. It looks like on your platform char is signed, so this value is actually -6.

Arithmetic operations on integer types smaller than int get promoted to int before the operation is performed. From cppreference on Integer promotion :

prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable. This conversion always preserves the value.

Note the last sentence : "This conversion always preserves the value". The value being preserved in this case is -6 not 250. The char is promoted to an int with the value -6 with a resulting of (assuming 32 bit int) 0xFFFFFFFA. The same thing occurs for the left operand, but the preserved value is 0, which is unchanged by the bitshift. Bitwise OR is then performed resulting in 0xFFFFFFFA, and then truncated to uint16_t for 0xFFFA or 65530.

One solution is to cast the char to unsigned char first to allow the promotion to preserve the intended value, 250 in this case.

Live example : https://godbolt.org/z/PP8rKqab7

  •  Tags:  
  • c qt
  • Related