我的一个功课问题是获取一系列字节,用无符号整数表示,然后复制某个字节,从而将系列扩展一个字节。例如,如果我在十六进制表示为0xAABBCC的无符号整数上执行此函数,同时指定扩展第二个字节,则在此函数之前和之后输出十六进制值将如下所示:
0xAABBCC -> 0xAABBBBCC
我已经取得了一些进展,因为我觉得我确实理解了按位运算符,但是我没有看到如何使用按位运算符来执行像这样的更复杂的任务。看到这是一个家庭作业的问题,我很乐意将答案简单地链接到关于按位运算符的文章,但请记住,我确实已经掌握了基础知识,并且我更愿意看到一些按位的系列实例行动中的行动。
这是我到目前为止的代码。它似乎接近于工作,但我无法掌握如何将重复的字节插入到字节序列的中间。
unsigned long long extend_byte(unsigned x, unsigned i) //x = 0xAABBCC, i = 1
{
printf("%x\n", x); //0xaabbcc
int shiftVal = i << 3;
unsigned mask = 0xFF << shiftVal;
printf("%x\n", mask); //0x00ff
unsigned byteToCopy = x | ~mask;
printf("%x\n", byteToCopy); //0xffffbbff
x &= byteToCopy;
printf("%x\n", x); //aabbcc
return x;
}
答案 0 :(得分:0)
问题是你的掩码屏蔽了一个字节,你需要屏蔽要复制的字节右边的所有数字,并使用不同的掩码,屏蔽该字节左边的所有数字。检查以下内容:
uint64_t extend_byte(uint64_t x, uint64_t i) // 0x0000000011223344 and 3
{
uint64_t allOnes = ~0x00ULL; // 0xFFFFFFFFFFFFFFFF
uint64_t shiftVal = i << 3; // i << 3 == i * 8 == 24 bits = 3 bytes
uint64_t leftMask = allOnes << shiftVal; // 0xFFFFFFFFFF000000
uint64_t leftPart = (x << 8) & leftMask; // 0x0000001122000000
uint64_t rightMask = ~leftMask; // 0x0000000000FFFFFF
uint64_t rightPart = x & ~rightMask; // 0x0000000000223344
return leftPart | rightPart; // 0x0000001122223344
}
我认为解决这类问题的诀窍是一步一步地使用所有前导零,这样你就可以看到字节是如何移动的。
答案 1 :(得分:0)
这是我提出的代码。大部分的想法都在评论中解释。
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
/*
** Given input value = 0x00AABBCC,
** for i = 0, output = 0xAABBCCCC
** for i = 1, output = 0xAABBBBCC
** for i = 2, output = 0xAAAABBCC
**
** There's a RHS, MID and LHS section.
** The MID section corresponds to the byte to be replicated.
** The RHS section corresponds to the (possibly empty) set of bytes to be
** left unchanged -- the bytes to the right of the mid section.
** The LHS section corresponds to the more significant bytes to the left
** of the mid section.
**
** Zero bytes in RHS section: (input & ~rhs_mask)
** Shift the result to the left: (input & ~rhs_mask) << 8
** Insert the MID and RHS sections once more:
** ((input & ~rhs_mask) << 8) | (input & (mid_mask & rhs_mask))
**
** For i = 0:
** rhs_mask = 0x00000000
** mid_mask = 0x000000FF
** For i = 1:
** rhs_mask = 0x000000FF
** mid_mask = 0x0000FF00
** For i = 2:
** rhs_mask = 0x0000FFFF
** mid_mask = 0x00FF0000
**
** RHS mask corresponds to 'all bits one' shifted left by 8*i, then
** bitwise inverted: ~((~UINT64_C(0) << (8 * i))
*/
static uint64_t extend_byte(uint64_t input, unsigned i)
{
assert(i < sizeof(input));
//printf("Input: 0x%.8" PRIX64 " shift %u\n", input, i);
uint64_t mid_mask = UINT64_C(0xFF) << (8 * i);
//printf("Mid mask: 0x%.8" PRIX64 ", mid value = 0x%.8" PRIX64 "\n", mid_mask, input & mid_mask);
uint64_t rhs_mask = ~((~UINT64_C(0)) << (8 * i));
//printf("RHS mask: 0x%.8" PRIX64 ", RHS value = 0x%.8" PRIX64 "\n", rhs_mask, input & rhs_mask);
uint64_t output = ((input & ~rhs_mask) << 8) | (input & (mid_mask | rhs_mask));
//printf("Output: 0x%.8" PRIX64 "\n", output);
return output;
}
int main(void)
{
uint64_t input;
input = 0x00AABBCC;
for (unsigned i = 0; i < 4; i++)
printf("0x%.8" PRIX64 " shift %u = 0x%.8" PRIX64 "\n", input, i, extend_byte(input, i));
putchar('\n');
input = 0x88776655FFEEDDCC;
for (unsigned i = 0; i < 8; i++)
printf("0x%.8" PRIX64 " shift %u = 0x%.8" PRIX64 "\n", input, i, extend_byte(input, i));
putchar('\n');
return 0;
}
测试工具的示例输出:
0x00AABBCC shift 0 = 0xAABBCCCC
0x00AABBCC shift 1 = 0xAABBBBCC
0x00AABBCC shift 2 = 0xAAAABBCC
0x00AABBCC shift 3 = 0x00AABBCC
0x88776655FFEEDDCC shift 0 = 0x776655FFEEDDCCCC
0x88776655FFEEDDCC shift 1 = 0x776655FFEEDDDDCC
0x88776655FFEEDDCC shift 2 = 0x776655FFEEEEDDCC
0x88776655FFEEDDCC shift 3 = 0x776655FFFFEEDDCC
0x88776655FFEEDDCC shift 4 = 0x77665555FFEEDDCC
0x88776655FFEEDDCC shift 5 = 0x77666655FFEEDDCC
0x88776655FFEEDDCC shift 6 = 0x77776655FFEEDDCC
0x88776655FFEEDDCC shift 7 = 0x88776655FFEEDDCC
AFAICT,answer的修订版5 MondKin会产生错误的结果。当替换我的byte_extend()
版本时,它会产生输出:
0x00AABBCC shift 0 = 0xAABBFFCC
0x00AABBCC shift 1 = 0xAABBFF00
0x00AABBCC shift 2 = 0xAABB0000
0x00AABBCC shift 3 = 0xAA000000
0x88776655FFEEDDCC shift 0 = 0xFF7777FFFFFFDDCC
0x88776655FFEEDDCC shift 1 = 0xFF7777FFFFFFDD00
0x88776655FFEEDDCC shift 2 = 0xFF7777FFFFFF0000
0x88776655FFEEDDCC shift 3 = 0xFF7777FFFF000000
0x88776655FFEEDDCC shift 4 = 0xFF7777FF00000000
0x88776655FFEEDDCC shift 5 = 0xFF77770000000000
0x88776655FFEEDDCC shift 6 = 0xFF77000000000000
0x88776655FFEEDDCC shift 7 = 0xFF00000000000000