如何从长指针中提取 little-endian unsigned short?

Posted

技术标签:

【中文标题】如何从长指针中提取 little-endian unsigned short?【英文标题】:How do I extract little-endian unsigned short from long pointer? 【发布时间】:2018-07-11 10:37:43 【问题描述】:

我有一个长指针值,它指向一个 20 字节的标头结构,后跟一个更大的数组。十二月(57987104)=十六进制(0374D020)。所有值都以小端方式存储。 1400交换时为0014,十进制为20。

这里的问题是如何获得第一个 2 字节无符号短值。我有一个 C++ dll 可以为我转换它。我正在运行 Windows 10。

GetCellData_API unsigned short __stdcall getUnsignedShort(unsigned long ptr) 

    unsigned long *p = &ptr;
    unsigned short ret = *p;
    return ret;

但是当我使用 Debug.Print getUnsignedShort(57987104) 从 VBA 调用它时,我得到 30008,而它应该是 20。

我可能需要进行字节序交换,但我不确定如何从 CodeGuru: How do I convert between big-endian and little-endian values? 合并它

inline void endian_swap(unsigned short& x)

    x = (x >> 8) |
        (x << 8);

如何从长指针中提取 little endian unsigned short?

【问题讨论】:

第二个无符号短值恰好为零。 【参考方案1】:

我想我会倾向于用描述操作的通用模板函数来编写你的接口函数:

#include <utility>
#include <cstdint>

// Code for the general case
// you'll be amazed at the compiler's optimiser
template<class Integral>
auto extract_be(const std::uint8_t* buffer)

    using accumulator_type = std::make_unsigned_t<Integral>;

    auto acc = accumulator_type(0);
    auto count = sizeof(Integral);

    while(count--)
    
        acc |= accumulator_type(*buffer++) << (8 * count);
    

    return Integral(acc);




GetCellData_API unsigned short __stdcall getUnsignedShort(std::uintptr_t ptr) 

    return extract_be<std::uint16_t>(reinterpret_cast<const std::uint8_t*>(ptr));

正如您从demo on godbolt 中看到的那样,编译器会为您完成所有艰苦的工作。

请注意,由于我们知道数据的大小,因此我使用了从 &lt;cstdint&gt; 导出的大小整数类型,以防需要将此代码移植到另一个平台。

编辑:

刚刚意识到您的数据实际上是 LITTLE ENDIAN :)

template<class Integral>
auto extract_le(const std::uint8_t* buffer)

    using accumulator_type = std::make_unsigned_t<Integral>;

    auto acc = accumulator_type(0);
    constexpr auto size = sizeof(Integral);

    for(std::size_t count = 0 ; count < size ; ++count)
    
        acc |= accumulator_type(*buffer++) << (8 * count);
    

    return Integral(acc);



GetCellData_API unsigned short __stdcall getUnsignedShort(std::uintptr_t ptr) 

    return extract_le<std::uint16_t>(reinterpret_cast<const std::uint8_t*>(ptr));

【讨论】:

这是否易于转换以获得标题其余部分的长值? (仍在阅读/理解/测试) @D_Bester "所有的值都是大端存储的。"我想你的意思是说“小端” 有了你的新版本,我回到了-19957。还是不行。 @D_Bester 你能在coliru.stacked-crooked.com 上发布一个 MCVE 并与我分享以演示这个问题吗? @D_Bester 因为它对我有用:coliru.stacked-crooked.com/a/2b82f5e3a7b627ca【参考方案2】:

假设你用 pulong pulong[6] 指点你指的是表的第六个成员

unsigned short psh*; unsigned char puchar* unsigend char ptable[4]; ZeroMemory(ptable,4); puchar[3]=((char *)( &pulong[6]))[0]; puchar[2]=((char *)( &pulong[6]))[1]; puchar[1]=((char *)( &pulong[6]))[2]; puchar[0]=((char *)( &pulong[6]))[3]; psh=(unsigned short *) puchar; //first one psh[0]; //second one psh[1]; 这就是我误会时的想法

【讨论】:

这不能回答我的问题。它甚至不编译。我看不到如何将指针放入您的代码中,并且它不输出任何十进制值。所以这似乎与我无关。 如果这与endian_swap 有关,那么您错过了我的问题,应该删除这个答案。我什至不知道endian_swap 是否与我的问题相关。我认为不是。 感谢您的宝贵时间。

以上是关于如何从长指针中提取 little-endian unsigned short?的主要内容,如果未能解决你的问题,请参考以下文章

从长的复杂日期加上时间戳中提取日期?

如何从长轮询中获取响应数据?

如何从长字符串中获取电子邮件地址

即使项目不连续使用Python,如何从长嵌套列表中删除短列表?

如何使用 C++ 中的位操作从长变量中破译 4 个短变量?

如何将数据框从长转换为宽,索引中的值按年份分组?