短包装/拆包到内部

Pack/unpack short into int

本文关键字:内部 包装      更新时间:2023-10-16

我想将两个有符号的16位整数打包/解压缩为一个32位整数。然而,我并没有让它完全发挥作用。

关于我可能做错了什么,有什么想法吗?

template <typename T>
int read_s16(T& arr, int idx) restrict(amp)
{
    return static_cast<int>((arr[idx/2] >> ((idx % 2) * 16)) << 16) >> 16;
}
template<typename T>
void write_s16(T& arr, int idx, int val) restrict(amp)
{
    // NOTE: arr is zero initialized
    concurrency::atomic_fetch_or(&arr[idx/2], (static_cast<unsigned int>(val) & 0xFFFF) << ((idx % 2) * 16));
}

函数返回/参数必须与我定义的一样。lohi是从不同的线程(因此是atomic_or)写入的,读取必须返回一个32位的值。

目标平台不支持16位整数算法。

示例:

array<int> ar(1); // Container
write_s16(ar, 0, -16);
write_s16(ar, 1, 5);
assert(read_s16(ar, 0) == -16);
assert(read_s16(ar, 1) == 5);

它看起来过于复杂,而且里面有一些奇怪的操作。

通常,你只会这样做:

int32_t Pack(int16_t a, int16_t b)
{
   return (int32_t)((((uint32_t)a)<<16)+(uint32_t)b);
}
int16_t UnpackA(int32_t x)
{
   return (int16_t)(((uint32_t)x)>>16);
}
int16_t UnpackB(int32_t x)
{
   return (int16_t)(((uint32_t)x)&0xffff);
}

请注意,我使用了具有显式位大小的类型来说明发生了什么。我还随意假设你想要一个"整数",而不是"无符号整数"。

C++AMP中的这些原子操作也有以下限制:

  • 您不应该混合原子和普通(非原子)读写。正常读取可能看不到原子写入相同内存位置。普通写入不应与原子写入混合到相同的存储器位置。如果您的程序不符合那么这些标准将导致未定义的结果
  • 原子操作并不意味着任何类型的内存围栏。原子操作可以重新订购。这与互锁的行为不同C++中的操作

你似乎违反了其中的第一条。

下面的代码在MSVC中运行良好。正如您所看到的,原则上它与您的代码是一样的

问题可能是您忘记将数组的内容初始化为零吗?您的平台如何处理负数和转换为无符号int?

template <typename T>
int read_s16(T& arr, int idx)
{
    return static_cast<int>((arr[idx/2] >> ((idx % 2) * 16)) << 16) >> 16;
}
template<typename T>
void write_s16(T& arr, int idx, int val)
{
    // NOTE: arr is zero initialized
    arr[idx/2] |= (static_cast<unsigned int>(val) & 0xFFFF) << ((idx % 2) * 16);
}
int main()
{
    int ar[2] = { 0,0 }; // container
    write_s16<int [2]>(ar, 0, -16);
    write_s16<int [2]>(ar, 1, 5);
    assert(read_s16<int [2]>(ar, 0) == -16);
    assert(read_s16<int [2]>(ar, 1) == 5);
    return 0;
}

试试这个包装:

int_32 = (int16_1 & 0x0000FFFF) | (int16_2 & 0xFFFF0000);

用于开箱:

int16_MSB = (int_32 >> 16) & 0xFFFF;
int16_LSB = int_32 & 0xFFFF;