如何无循环实现大无符号数据类型向unsigned char的缩放转换?
问题描述
我有一个无符号数据类型T*的大型数组,需要将其转换为unsigned char*并进行值缩放。例如从unsigned short*转换为unsigned char*时,{0,..,255}范围的值需映射为0,{65281,..,65535}范围的值需映射为255。
常规方法是通过循环结合位运算实现:
const T x = some_large_value; unsigned char y = (x >> (8u * (sizeof(T) - 1u))); // 等效于截断式的 "x/(256^{sizeof(T)-1})"
但我希望避免此类方案中的for (..)循环,曾设想支持step参数的super-memcpy:
// Intel处理器,小端字节序,假设数组有N个元素 const T* src = ..; const unsigned char* src_uchar = reinterpret_cast<const unsigned char*>(src); memcpy(dst_uchar, src_uchar + (sizeof(T) - 1u), N, step=sizeof(T)-1u);
但带step参数的memcpy并不存在,请问是否有其他命令可实现等效效果?
可行方案
1. 使用标准库std::transform
这是最便捷的标准库替代方案,无需手动编写循环,编译器会自动优化循环逻辑,甚至可能进行矢量化优化提升性能。核心是用一个转换函数(或lambda)定义每个元素的缩放规则,由std::transform批量处理数组元素。
2. 编译器内置/SIMD指令(极致性能场景)
如果追求最高性能,针对x86平台可以使用Intel SSE/AVX等SIMD指令集,或编译器内置函数(如_mm_shuffle_epi16、_mm256_extracti_epi16等)批量处理数据,一次性完成多个元素的转换。不过这种方式需要处理内存对齐、剩余元素收尾等细节,实现复杂度较高。
演示程序(基于
std::transform) 感谢pptaszni的提议,以下是使用std::transform实现uint16数组向uint8转换的演示程序(位运算缩小值域的逻辑同样适用于有符号类型):
#include <algorithm> #include <iostream> using namespace std; int main() { // 输入数组A,输出数组B const unsigned short A[] = {60000u, 50000u, 30000u, 1000u, 500u, 300u, 200u}; unsigned char B[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u}; // 定义转换逻辑的lambda表达式 auto transformation = [](const unsigned short& elem) { return static_cast<unsigned char>(elem >> 8u * (sizeof(decltype(elem))-1)); }; // 执行UINT16到UINT8的缩容转换 std::transform(A, A+7, B, transformation); // 输出转换结果 for (size_t j=0; j<7; ++j) { cout << A[j] << " => " << ((unsigned short)B[j]) << endl; } return 0; }
程序输出:
60000 => 234 50000 => 195 30000 => 117 1000 => 3 500 => 1 300 => 1 200 => 0
内容的提问来源于stack exchange,提问作者Markus-Hermann
相关产品推荐
相关产品推荐

