为什么 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) = 0
和 usbDataRaw.at(byteIndex + 1) = 250
.
但是当我将它们组合在一起时,如您所见,我得到了数字 65530
!
这很有趣,因为 -6/250
是 0xFA
或 250
。这意味着 0
必须变成 0xFF
对吗?为什么 250
会变成 65530
?
未指定char
是signed
还是unsigned
。
usbDataRaw.at(byteIndex + 1)
导致 char
打算存储值 250
。在你的平台上看起来 char
是 signed
,所以这个值实际上是 -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
而不是 250
。 char
被提升为值为 -6
的 int
,结果为(假设 32 位 int
)0xFFFFFFFA
。同样的事情发生在左操作数上,但是保留的值是0
,它没有被移位改变。然后执行按位 OR 得到 0xFFFFFFFA
,然后截断为 uint16_t
以获得 0xFFFA
或 65530
.
一个解决方案是首先将 char
转换为 unsigned char
以允许促销保留预期值,在本例中为 250
。
通过 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) = 0
和 usbDataRaw.at(byteIndex + 1) = 250
.
但是当我将它们组合在一起时,如您所见,我得到了数字 65530
!
这很有趣,因为 -6/250
是 0xFA
或 250
。这意味着 0
必须变成 0xFF
对吗?为什么 250
会变成 65530
?
未指定char
是signed
还是unsigned
。
usbDataRaw.at(byteIndex + 1)
导致 char
打算存储值 250
。在你的平台上看起来 char
是 signed
,所以这个值实际上是 -6
.
小于 int
的整数类型的算术运算在执行操作之前被提升为 int
。来自 Integer promotion 上的 cppreference :
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.
注意最后一句话:“此转换始终保留值”。在这种情况下保留的值是 -6
而不是 250
。 char
被提升为值为 -6
的 int
,结果为(假设 32 位 int
)0xFFFFFFFA
。同样的事情发生在左操作数上,但是保留的值是0
,它没有被移位改变。然后执行按位 OR 得到 0xFFFFFFFA
,然后截断为 uint16_t
以获得 0xFFFA
或 65530
.
一个解决方案是首先将 char
转换为 unsigned char
以允许促销保留预期值,在本例中为 250
。