为什么 char 0x0 在 QT C++ QByteArray 中变为 0xFF (255)?

Why does char 0x0 becomes 0xFF (255) in QT C++ QByteArray?

通过 USB,我将以下内容发送到我的 QT C++ 应用程序。如您所见,我们向我的 QT C++ 应用程序发送了总共 5 个字节的数据。

/* 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);

当我发送数据时,它看起来像这样:

所以当我在我的 QT C++ 应用程序中收到数据时,它看起来像这样:

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];

其中 usbDataRaw 包含数据。 usbDataRaw 的第一个索引包含描述消息类型的 message type。所以上面的代码从索引 1 开始,而不是索引 0.

让我们关注

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

此处 pwmPrescaler 声明为 uint16_t pwmPrescaler[2]; 并且 usbDataRaw.at(byteIndex) = 0usbDataRaw.at(byteIndex + 1) = 250.

但是当我将它们组合在一起时,如您所见,我得到了数字 65530!

这很有趣,因为 -6/2500xFA250。这意味着 0 必须变成 0xFF 对吗?为什么 250 会变成 65530

未指定charsigned还是unsigned

usbDataRaw.at(byteIndex + 1) 导致 char 打算存储值 250。在你的平台上看起来 charsigned,所以这个值实际上是 -6.

小于 int 的整数类型的算术运算在执行操作之前被提升为 int。来自 Integer promotion 上的 cppreference :

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.

注意最后一句话:“此转换始终保留值”。在这种情况下保留的值是 -6 而不是 250char 被提升为值为 -6int,结果为(假设 32 位 int0xFFFFFFFA。同样的事情发生在左操作数上,但是保留的值是0,它没有被移位改变。然后执行按位 OR 得到 0xFFFFFFFA,然后截断为 uint16_t 以获得 0xFFFA65530.

一个解决方案是首先将 char 转换为 unsigned char 以允许促销保留预期值,在本例中为 250

实例:https://godbolt.org/z/PP8rKqab7