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:
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
!
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
?
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 asint
). In particular, arithmetic operators do not accept types smaller thanint
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