繁体   English   中英

在无符号char数组中设置无符号short

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM