在C中,给定一系列字节,如何复制一个字节然后复制该字节?

时间:2017-09-22 04:35:15

标签: c bit-manipulation bitwise-operators

我的一个功课问题是获取一系列字节,用无符号整数表示,然后复制某个字节,从而将系列扩展一个字节。例如,如果我在十六进制表示为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;
}

2 个答案:

答案 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
相关问题