[英]Setting an unsigned short in an unsigned char array
我有以下typedef
typedef unsigned char BYTE;
typedef unsigned short WORD;
现在,我有一个看起来像这样的数组
BYTE redundantMessage[6];
和一个看起来像这样的领域
WORD vehicleSpeedToWord = static_cast<WORD>(redundantVelocity);
我想将此消息的第三和第四字节设置为vehicleSpeedToWord
的值。 请问这样做:
redundantMessage[3] = vehicleSpeedToWord;
redundantMessage
的第三个字节会自动被覆盖吗?
我想设置此消息的第三和第四字节[fn。 冗余消息]设置为vehicleSpeedToWord的值。
小尾数法还是大尾数法 ? 假设unsigned short
正好是16位(!)(即sizeof(unsigned short) == 2 && CHAR_BIT == 8
,则:
// little endian
// set the third byte of redundantMessage to (vehicleSpeedToWord&0xff)
redundantMessage[2] = vehicleSpeedToWord;
// sets the fourth byte of redundantMessage to ((vehicleSpeedToWord&0xff00)>>8)
redundantMessage[3] = vehicleSpeedToWord>>8;
要么
// big endian
redundantMessage[2] = vehicleSpeedToWord>>8;
redundantMessage[3] = vehicleSpeedToWord;
如果要使用主机的字节性,则需要告诉编译器分配WORD
数据:
*reinterpret_cast<WORD*>(&redundantMessage[2]) = vehicleSpeedToWord;
但这不是真的可靠。
short不是16位,而是至少 16位。 因此,在x64机器上可能是64位,在1024位机器上可能是1024位。 最好使用固定宽度的整数类型 :
#include <cstdint>
typedef uint8_t BYTE;
typedef uint16_t WORD;
如您所建议,最好的方法是使用std::memcpy()
。 但是,您需要传递地址,而不是值。 如果您的意思是第三个和第四个字节,则应从2
开始,而不是3
:
std::memcpy(&redundantDataMessage[2], vehicleSpeedToWord, sizeof(vehicleSpeedToWord));
当然,您可以通过摆弄这些位来“手动”进行操作,例如(假设CHAR_BIT == 8
):
const BYTE high = vehicleSpeedToWord >> 8;
const BYTE low = vehicleSpeedToWord & static_cast<WORD>(0x00FF);
redundantDataMessage[2] = high;
redundantDataMessage[3] = low;
不必担心std::memcpy()
的性能,生成的代码应该相同。
您在评论中讨论的另一点是字节序。 如果要处理网络协议,则必须实现它们在其中指定的任何字节序; 然后进行相应的转换。 为此,最好的方法是预先使用某些函数将WORD
转换为适当的字节序(即,从您的arch的字节序到协议的字节序-如果它们匹配,此转换可能是标识函数)。
编译器/环境通常定义一组函数来处理这些问题。 如果需要可移植的代码,请将它们包装在自己的函数中或实现自己的函数,请参见如何在C ++中的大端值和小端值之间转换? 更多细节。
您没有说要以小字节序格式(例如,英特尔处理器)还是大字节序(网络字节顺序)存储数据。
这就是我要解决的方法。
我提供了两个版本进行比较。
#include <cstdint>
#include <type_traits>
#include <cstddef>
#include <iterator>
struct little_endian {}; // low bytes first
struct big_endian {}; // high bytes first
template<class T>
auto integral_to_bytes(T value, unsigned char* target, little_endian)
-> std::enable_if_t<std::is_unsigned_v<T>>
{
for(auto count = sizeof(T) ; count-- ; )
{
*target++ = static_cast<unsigned char>(value & T(0xff));
value /= 0x100;
}
}
template<class T>
auto integral_to_bytes(T value, unsigned char* target, big_endian)
-> std::enable_if_t<std::is_unsigned_v<T>>
{
auto count = sizeof(T);
auto first = std::make_reverse_iterator(target + count);
while(count--)
{
*first++ = static_cast<unsigned char>(value & T(0xff));
value /= 0x100;
}
}
int main()
{
extern std::uint16_t get_some_value();
extern void foo(unsigned char*);
unsigned char buffer[6];
std::uint16_t some_value = get_some_value();
// little_endian
integral_to_bytes(some_value, buffer + 3, little_endian());
foo(buffer);
// big-endian
integral_to_bytes(some_value, buffer + 3, big_endian());
foo(buffer);
}
您可以在这里查看生成的汇编程序。 您可以看到,无论哪种方式,编译器都能很好地完成将逻辑意图转换为高效代码的工作。
更新:我们可以改进样式,而无需在发射代码中付出任何代价。 现代的c ++编译器是惊人的:
#include <cstdint>
#include <type_traits>
#include <cstddef>
#include <iterator>
struct little_endian {}; // low bytes first
struct big_endian {}; // high bytes first
template<class T, class Iter>
void copy_bytes_le(T value, Iter first)
{
for(auto count = sizeof(T) ; count-- ; )
{
*first++ = static_cast<unsigned char>(value & T(0xff));
value /= 0x100;
}
}
template<class T, class Iter>
auto integral_to_bytes(T value, Iter target, little_endian)
-> std::enable_if_t<std::is_unsigned_v<T>>
{
copy_bytes_le(value, target);
}
template<class T, class Iter>
auto integral_to_bytes(T value, Iter target, big_endian)
-> std::enable_if_t<std::is_unsigned_v<T>>
{
copy_bytes_le(value,
std::make_reverse_iterator(target + sizeof(T)));
}
int main()
{
extern std::uint16_t get_some_value();
extern void foo(unsigned char*);
unsigned char buffer[6];
std::uint16_t some_value = get_some_value();
// little_endian
integral_to_bytes(some_value, buffer + 3, little_endian());
foo(buffer);
// big-endian
integral_to_bytes(some_value, buffer + 3, big_endian());
foo(buffer);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.