C语言:拼接不同long类型数据的部分位及实现指定位提取函数
嘿,这可是个典型的位操作问题,我一步步给你拆解清楚——先解决第一个拼接long类型部分内容的问题,再实现你要的getbits函数。
一、在C语言中拼接不同long类型的部分内容
核心就是用好三个位操作工具:
- 掩码(&):用来精准提取你需要的位段。比如要从一个
unsigned long里取低12位,就用value & 0xFFF;要取第20到27位(共8位),就先把数值右移20位,再用& 0xFF过滤出低8位:(value >> 20) & 0xFF。 - 移位(<<、>>):把提取到的位段挪到目标位置。比如刚才取的低12位要放到结果的高12位,就用
low_12_bits << (64 - 12)(假设是64位unsigned long)。 - 按位或(|):把不同的位段拼接成一个完整的数值。比如把高16位和低48位拼起来:
(high_16_bits << 48) | low_48_bits。
举个简单例子:假设我们有两个64位unsigned long变量a和b,要把a的高32位和b的低32位拼成新的unsigned long:
unsigned long a = 0xABCDEF001234567A; unsigned long b = 0x98761111FCDFEC80; unsigned long result = (a & 0xFFFFFFFF00000000) | (b & 0x00000000FFFFFFFF);
二、实现getbits函数
先从你的示例反推规则:
- 数组
bits是连续的位序列,bits[0]是高64位,bits[1]是低64位; - 位编号从0开始,第0位是整个序列的最低位(LSB)(也就是
bits[1]的第0位); - 调用
getbits(bits, 56, 20)要返回0x0000000000067A98,这意味着我们要提取从第56位到第75位的20位,这20位跨了bits[1]的56-63位(8位)和bits[0]的0-11位(12位),拼接后得到目标值。
基于这个逻辑,写出的函数如下:
#include <stddef.h> unsigned long getbits(unsigned long bits[], unsigned idx, unsigned len) { unsigned end_idx = idx + len - 1; // 这里假设数组固定为2个元素,如果要支持任意长度,可以添加数组长度参数 const size_t array_len = 2; // 计算起始位和结束位所在的数组元素索引 size_t start_elem = array_len - 1 - (idx / 64); size_t end_elem = array_len - 1 - (end_idx / 64); unsigned long result = 0; if (start_elem == end_elem) { // 所有位都在同一个元素中 unsigned shift = idx % 64; // 生成len位全1的掩码,注意用1UL避免溢出(len=64时用~0UL) unsigned long mask = (len == 64) ? ~0UL : ((1UL << len) - 1); result = (bits[start_elem] >> shift) & mask; } else { // 跨两个元素提取(示例就是这种情况) // 提取低位元素的目标部分(从idx到该元素的最高位) unsigned low_bits_len = 64 - (idx % 64); unsigned long low_part = bits[start_elem] >> (idx % 64); // 提取高位元素的目标部分(从该元素的最低位到end_idx) unsigned high_bits_len = len - low_bits_len; unsigned long high_part = bits[end_elem] & ((1UL << high_bits_len) - 1); // 拼接两部分:高位部分左移低位长度,再和低位部分按位或 result = (high_part << low_bits_len) | low_part; } return result; }
验证示例:
把bits = {0xABCDEF001234567A, 0x98761111FCDFEC80}传入函数:
idx=56,len=20,end_idx=75;start_elem=1(对应bits[1]),end_elem=0(对应bits[0]);- 从
bits[1]提取56-63位:0x98761111FCDFEC80 >>56得到0x98; - 从
bits[0]提取0-11位:0xABCDEF001234567A & 0xFFF得到0x67A; - 拼接:
(0x67A <<8) | 0x98 = 0x67A98,和示例预期结果一致。
补充说明:
- 如果你的数组存储顺序相反(
bits[0]是低64位),只需要调整start_elem和end_elem的计算方式,改成start_elem = idx /64即可; - 如果需要支持
len超过64位的情况,可以添加循环处理多个元素的逻辑; - 代码中用
1UL而不是1,是为了避免int类型左移溢出的问题,确保位操作在unsigned long的范围内进行。
内容的提问来源于stack exchange,提问作者Vegas
相关产品推荐
相关产品推荐

