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 thanintas 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



