网站的站点地图设计,餐饮网站建设的模板,怎么看网站有没有做竞价,自己开外包公司怎么接项目分享一个C的按位拷贝的代码。 由于标准库中所有的拷贝都是以字节为单位的#xff0c;而没有按位进行拷贝的。最近碰到了一个需要按位操作数据的情况#xff0c;写了一段代码。如有错误#xff0c;望请指摘。
#include cstdint
#include cstdlibclass BitOp…分享一个C的按位拷贝的代码。 由于标准库中所有的拷贝都是以字节为单位的而没有按位进行拷贝的。最近碰到了一个需要按位操作数据的情况写了一段代码。如有错误望请指摘。
#include cstdint
#include cstdlibclass BitOperator
{
public:/*** brief: 按位拷贝。如从{0x00, 0xff, 0xff, 0xff}中的第2位开始拷贝12位到{0x00, 0x00, 0x00, 0x00}* 的第5位开始。则得到{0x00, 0xf8, 0x01, 0x00}。* * 低地址 高地址* ↓ ↓* src: 0000 0000 1111 1111 1111 1111 1111 1111 {0x00, 0xff, 0xff, 0xff}* -- ---- ---- --* ↘* ___ ____ ____ _* dst: 0000 0000 0000 0000 0000 0000 0000 0000 {0x00, 0x00, 0x00, 0x00}* * res: 0000 0000 0001 1111 1000 0000 0000 0000 {0x00, 0xf8, 0x01, 0x00}* * param dst_bitmap 目标地址* param src_bitmap 源地址* param bit_length 要拷贝的位数* param dst_start_bit 起始位在目标字节中的index。该起始位会被包括在拷贝范围内。该值不应该超过7。* param src_start_bit 起始位在源地址指向的字节中的index。该起始位的位数据会被覆盖。该值不应该超过7。*/static inline void bitcpy(void* dst_bitmap,const void* src_bitmap,uint32_t bit_length,uint8_t dst_start_bit 0,uint8_t src_start_bit 0){// 不需要错位拷贝则起始和终止字节额外处理中间使用memcpyif (dst_start_bit src_start_bit){return __bitcpy(reinterpret_castuint8_t*(dst_bitmap),reinterpret_castconst uint8_t*(src_bitmap),bit_length,src_start_bit);}// 需要错位拷贝。// 需要源数据右移后拷贝至目的地址。else if (dst_start_bit src_start_bit){uint8_t diff src_start_bit - dst_start_bit;__bitcpyRIGHT_SHIFT(reinterpret_castuint32_t*(dst_bitmap),reinterpret_castconst uint32_t*(src_bitmap),bit_length,diff,src_start_bit);}// 需要源数据左移后拷贝至目的地址。else{uint8_t diff dst_start_bit - src_start_bit;__bitcpyLEFT_SHIFT(reinterpret_castuint32_t*(dst_bitmap),reinterpret_castconst uint32_t*(src_bitmap),bit_length,diff,src_start_bit);}}/*** brief: 位拷贝的安全版本会对输入参数进行检测。如果参数正确则返回true。否则返回false。* * param dst_bitmap 目标地址* param src_bitmap 源地址* param bit_length 要拷贝的位数* param dst_start_bit 起始位在目标字节中的index。该起始位会被包括在拷贝范围内。该值不应该超过7。* param src_start_bit 起始位在源地址指向的字节中的index。该起始位的位数据会被覆盖。该值不应该超过7。* return true 正确拷贝* return false 输入参数有问题*/static bool bitcpy_s(void* dst_bitmap,const void* src_bitmap,uint32_t bit_length,uint8_t dst_start_bit 0,uint8_t src_start_bit 0){// 输入检测if (dst_bitmap nullptr)return false;if (src_bitmap nullptr)return false;if (dst_start_bit 7)return false;if (src_start_bit 7)return false;if (bit_length 0)return true;bitcpy(dst_bitmap, src_bitmap, bit_length, dst_start_bit, src_start_bit);return true;}private:// 定义左移为true 右移为false。constexpr static bool LEFT_SHIFT true;constexpr static bool RIGHT_SHIFT false;private:/*** brief: 计算选中从start位开始bit_length长度的位的掩码。将数据与该掩码相与即可选中指定位。* 比如从第0位开始选中8位则掩码为0x0000 0000 0000 00FF。* * param start 起始位* param bit_length 位长度* return uint64_t 掩码*/inline static uint64_t calculate_mask(uint8_t start, uint8_t bit_length){uint64_t res 1ULL start;return (res bit_length) - res;}/*** brief: 计算源数据和目标数据起始位相同的情况。此时不需要错位复制。起始字节和终止字节单独处理中间使* 用memcpy即可。* * param dst_ptr 目标地址* param src_ptr 源地址* param bit_length 要拷贝的位数* param start_bit 起始位*/static void __bitcpy(uint8_t* dst_ptr,const uint8_t* src_ptr,uint32_t bit_length,uint8_t start_bit){// 如果要拷贝的数据在一个字节中则直接选中拷贝。if (start_bit bit_length 8){auto mask calculate_mask(start_bit, bit_length);*dst_ptr (*src_ptr mask) | (*dst_ptr (~mask));return;}//如果起始位不为0则第一个字节需要单独处理。if (start_bit ! 0){uint8_t mask (1U start_bit) - 1;*dst_ptr (*src_ptr mask) | (*dst_ptr (~mask));bit_length - 8 - start_bit;dst_ptr;src_ptr;}//中间的数据直接使用memcpy进行拷贝auto byte_size bit_length 3;memcpy(dst_ptr, src_ptr, byte_size);//如果最后有不完整的字节数据需要拷贝进行处理。bit_length 7;if (bit_length ! 0){dst_ptr byte_size;src_ptr byte_size;uint8_t mask (1 bit_length) - 1;*dst_ptr (*src_ptr mask) | (*dst_ptr (~mask));}}/*** brief: 以4字节为一个数据块拷贝一个数据块。将源地址起始的4字节内需要拷贝的数据全部拷贝至目标地址* 指向的8字节空间中。因为目标地址是按8字节进行考虑的因此不用对源数据进行切割。** tparam _Left_Shift 拷贝时需要左移还是右移* param dst_bitmap 目标地址* param src_bitmap 源地址* param bit_length 要拷贝的位数* param start_diff 源地址和目标地址的起始位之差。* param src_start_bit 起始位在源地址指向的字节中的index。该起始位的位数据会被覆盖。该值不应该超过7。*/template bool _Left_Shiftinline static void copy_4_bytes(void* dst_bitmap,const uint32_t* src_bitmap,uint8_t bit_length,uint8_t start_diff,uint8_t src_start_bit 0){// 从源地址获取数据uint64_t temp *src_bitmap;uint64_t mask calculate_mask(src_start_bit, bit_length);temp mask;// 左移或右移掩码与数据使其与目标地址所在的位置对齐if constexpr (_Left_Shift){temp start_diff;mask start_diff;}else{temp start_diff;mask start_diff;}//取出目标地址的数据并将源数据中选中的部分覆盖至目标数据中最后拷贝回目标地址uint64_t res (*reinterpret_castuint64_t*(dst_bitmap)) (~mask);res | temp;*reinterpret_castuint64_t*(dst_bitmap) res | temp;}/*** brief: 处理需要错位拷贝的情况。以4字节为一个数据块进行处理以减少循环次数。** tparam _Left_Shift 拷贝时需要左移还是右移* param dst_ptr 目标地址* param src_ptr 源地址* param bit_length 要拷贝的位数* param start_diff 源地址和目标地址的起始位之差。* param src_start_bit 起始位在源地址指向的字节中的index。该起始位的位数据会被覆盖。该值不应该超过7。*/template bool _Left_Shiftstatic void __bitcpy(uint32_t* dst_ptr,const uint32_t* src_ptr,uint32_t bit_length,uint8_t start_diff,uint8_t src_start_bit){// 如果待拷贝的数据均在一个数据块内直接进行拷贝。if (src_start_bit bit_length 32){copy_4_bytes_Left_Shift(dst_ptr, src_ptr, bit_length, start_diff, src_start_bit);return;}// 拷贝第一个数据块。copy_4_bytes_Left_Shift(dst_ptr, src_ptr, 32 - src_start_bit, start_diff, src_start_bit);bit_length - 32 - src_start_bit;// 如果需要左移则目标地址的第一个数据块已经被填充完毕指向下一个数据块if constexpr (_Left_Shift)dst_ptr;// 如果需要右移则目标地址的第一个数据块未被全部填充计算尚未被填充的起始位。此时后面的数据拷贝又// 退化为了需要左移elsestart_diff 32 - start_diff;// 拷贝中间的数据块.while (bit_length 32){copy_4_bytesLEFT_SHIFT(dst_ptr, src_ptr, 32, start_diff);bit_length - 32;}// 拷贝最后一个数据块.copy_4_bytesLEFT_SHIFT(dst_ptr, src_ptr, bit_length, start_diff);}
};