我有以下typedef
typedef unsigned char BYTE;
typedef unsigned short WORD;
现在,我有一个看起来像这样的数组
BYTE redundantMessage[6];
和一个看起来像这样的字段
WORD vehicleSpeedToWord = static_cast<WORD>(redundantVelocity);
我想将此消息的第三个和第四个字节设置为值
vehicleSpeedToWord
。这会这样做:
redundantMessage[3] = vehicleSpeedToWord;
redundantMessage
的第三个字节是否会被自动覆盖?
答案 0 :(得分:0)
我想设置此消息的第三个和第四个字节[fn。 redundantMessage]到vehicleSpeedToWord的值。
Little endian or big endian?
假设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;
如果要使用主机endianess,则需要告诉编译器分配WORD
数据:
*reinterpret_cast<WORD*>(&redundantMessage[2]) = vehicleSpeedToWord;
但这不太可靠 short不是16位,而是至少 16位。因此它可能是x64机器上的64位,或1024位机器上的1024位。最好使用fixed width integer types:
#include <cstdint>
typedef uint8_t BYTE;
typedef uint16_t WORD;
答案 1 :(得分:0)
正如您所建议的,最好的方法是使用std::memcpy()
。但是,您需要传递地址,而不是值;如果你真的是指第三个和第四个字节,它应该从2
开始,而不是3
:
std::memcpy(&redundantDataMessage[2], vehicleSpeedToWord, sizeof(vehicleSpeedToWord));
当然,你可以这样做&#34;手动&#34;通过摆弄比特,例如(假设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的endianness到协议的endianness - 如果转换可能是身份函数,则他们匹配)。
编译器/环境通常定义一组函数来处理它。如果您需要可移植代码,将它们包装在您自己的函数中或实现自己的代码,请参阅How do I convert between big-endian and little-endian values in C++?以获取更多详细信息。
答案 2 :(得分:-1)
您没有说您是希望数据以小端格式(例如英特尔处理器)还是大端(网络字节顺序)存储。
以下是我将如何解决这个问题。
我提供了两个版本进行比较。
#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);
}
您可以查看生成的汇编程序here。您可以看到,无论哪种方式,编译器都能很好地将逻辑意图转换为非常高效的代码。
更新:我们可以在没有成本的情况下改进样式。现代的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);
}