简体   繁体   English

用1向右移动数组

[英]Shift an array to the right with 1

I'm trying to shift an array of unsigned char to the right with some binary 1. 我正在尝试使用一些二进制1将无符号char数组移到右侧。

Example: 0000 0000 | 例如:0000 0000 | 0000 1111 that I shift 8 times will give me 0000 1111 | 我换8次的0000 1111将给我0000 1111 | 1111 1111 (left shift in binary) 1111 1111(二进制左移)

So in my array I will get: {0x0F, 0x00, 0x00, 0x00} => {0xFF, 0x0F, 0x00, 0x00} (right shift in the array) 因此,在我的数组中,我将得到:{0x0F,0x00,0x00,0x00} => {0xFF,0x0F,0x00,0x00}(数组中的右移)

I currently have this using the function memmove: 我目前使用函数memmove拥有此功能:

unsigned char * dataBuffer = {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

unsigned int shift = 4;
unsigned length = 8;

memmove(dataBuffer, dataBuffer - shift, length + shift);    
for(int i = 0 ; i < 8 ; i++) printf("0x%X ", dataBuffer[i]);

Output: 0x0 0x0 0x0 0x0 0xF 0x0 0x0 0x0
Expected output: 0xFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0

As you can see, I managed to shift my array only element by element and I don't know how to replace the 0 with 1. I guess that using memset could work but I can't use it correctly. 如您所见,我设法逐个元素移动了仅数组元素,但我不知道如何用1替换0。我猜想使用memset可以工作,但我不能正确使用它。

Thanks for your help! 谢谢你的帮助!

EDIT: It's in order to fill a bitmap zone of an exFAT disk. 编辑:这是为了填充exFAT磁盘的位图区域。 When you write a cluster in a disk, you have to set the corresponding bit of the bitmap to 1 (first cluster is first bit, second cluster is second bit, ...). 在磁盘中写入群集时,必须将位图的相应位设置为1(第一个群集是第一位,第二个群集是第二位,...)。

A newly formatted drive will contain 0x0F in the first byte of the bitmap so the proposed example corresponds to my needs if I write 8 clusters, I'll need to shift the value 8 times and fill it with 1. 新格式化的驱动器在位图的第一个字节中将包含0x0F,因此如果编写8个簇,建议的示例与我的需求相对应,我需要将值移位8次并用1填充。

In the code, I write 4 cluster and need to shift the value by 4 bits but it is shifted by 4 bytes. 在代码中,我编写了4个簇,需要将值移位4位,但是将其移位4个字节。

Setting the question as solved, it isn't possible to do what I want. 将问题设置为已解决,就无法做我想要的事情。 Instead of shifting the bits of an array, I need to shift each byte of the array separately. 除了需要移位数组的位,还需要分别移位数组的每个字节。

Setting the question as solved, it isn't possible to do what I want. 将问题设置为已解决,就无法做我想要的事情。 Instead of shifting the bits of an array, I need to edit each bit of the array separately. 无需移动数组的位,而是需要分别编辑数组的每个位。

Here's the code if it can help anyone else: 这是可以帮助其他人的代码:

unsigned char dataBuffer[11] = {0x0F, 0x00, 0x00, 0x00, 0, 0, 0, 0};
unsigned int sizeCluster = 6;
unsigned int firstCluster = 4;
unsigned int bitIndex = firstCluster % 8;
unsigned int byteIndex = firstCluster / 8;
for(int i = 0 ; i < sizeCluster; i++){
    dataBuffer[byteIndex] |= 1 << bitIndex;
    //printf("%d ", bitIndex);
    //printf("%d \n\r", byteIndex);
    bitIndex++;
    if(bitIndex % 8 == 0){
        bitIndex = 0;
        byteIndex++;
    }
}
for(int i = 0 ; i < 10 ; i++) printf("0x%X ", dataBuffer[i]);

OUTPUT: 0xFF 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 

sizeCluster is the number of clusters I want to add in the Bitmap firstCluster is the first cluster where I can write my data (4 clusters are used: 0, 1, 2, and 3 so I start at 4). sizeCluster是我要在位图中添加的簇数firstCluster是我可以写入数据的第一个簇(使用了4个簇:0、1、2和3,所以我从4开始)。 bitIndex is used to modify the right bit in the byte of the array => increments each time. bitIndex用于修改数组字节中的右位=>每次递增。 byteIndex is used to modify the right byte of the array => increments each time the bit is equal to 7. byteIndex用于修改数组的右字节=>每当该位等于7时就递增。

In case you don't want to use C++ std::bitset for performance reasons, then your code can be rewrote like this: 如果出于性能原因不想使用C ++ std :: bitset,则可以按如下方式重写代码:

#include <cstdio>
#include <cstdint>

    // buffer definition
    constexpr size_t clustersTotal = 83;
    constexpr size_t clustersTotalBytes = (clustersTotal+7)>>3; //ceiling(n/8)
    uint8_t clustersSet[clustersTotalBytes] = {0x07, 0};
        // clusters 0,1 and 2 are already set (for show of)

    // helper constanst bit masks for faster bit setting
    // could be extended to uint64_t and array of qwords on 64b architectures
    // but I couldn't be bothered to write all masks by hand.
    // also I wonder when the these lookup tables would be large enough
    // to disturb cache locality, so shifting in code would be faster.
    const uint8_t bitmaskStarting[8] = {0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80};
    const uint8_t bitmaskEnding[8] = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
    constexpr uint8_t bitmaskFull = 0xFF;

    // Input values
    size_t firstCluster = 6;
    size_t sizeCluster = 16;

    // set bits (like "void setBits(size_t firstIndex, size_t count);" )
    auto lastCluster = firstCluster + sizeCluster - 1;
    printf("From cluster %d, size %d => last cluster is %d\n",
           firstCluster, sizeCluster, lastCluster);
    if (0 == sizeCluster || clustersTotal <= lastCluster)
        return 1;     // Invalid input values
    auto firstClusterByte = firstCluster>>3; // div 8
    auto firstClusterBit = firstCluster&7;   // remainder
    auto lastClusterByte = lastCluster>>3;
    auto lastClusterBit = lastCluster&7;
    if (firstClusterByte < lastClusterByte) {
        // Set the first byte of sequence (by mask from lookup table (LUT))
        clustersSet[firstClusterByte] |= bitmaskStarting[firstClusterBit];
        // Set bytes between first and last (simple 0xFF - all bits set)
        while (++firstClusterByte < lastClusterByte)
            clustersSet[firstClusterByte] = bitmaskFull;
        // Set the last byte of sequence (by mask from ending LUT)
        clustersSet[lastClusterByte] |= bitmaskEnding[lastClusterBit];
    } else {    //firstClusterByte == lastClusterByte special case
        // Intersection of starting/ending LUT masks is set
        clustersSet[firstClusterByte] |=
            bitmaskStarting[firstClusterBit] & bitmaskEnding[lastClusterBit];
    }

    for(auto i = 0 ; i < clustersTotalBytes; ++i)
        printf("0x%X ", clustersSet[i]); // Your debug display of buffer

Unfortunately I didn't profile any of the versions (yours vs my), so I have no idea what is the quality of optimized C compiler output in both cases. 不幸的是,我没有介绍任何版本(您与我的版本),所以我不知道在两种情况下优化的C编译器输出的质量如何。 In the ages of lame C compilers and 386-586 processors my version would be much faster. 在la脚的C编译器和386-586处理器时代,我的版本会更快。 With modern C compiler the LUT usage can be a bit counterproductive, but unless somebody proves me wrong by some profiling results, I still think my version is much more efficient. 使用现代C编译器,LUT的使用可能会适得其反,但是除非有人通过某些分析结果证明我错了,否则我仍然认为我的版本会更高效。

That said, as writing to file system is probably involved ahead of this, setting bits will probably take about %0.1 of CPU time even with your variant, I/O waiting will be major factor. 就是说,由于在此之前可能涉及写入文件系统,因此即使使用您的变量,设置位也可能需要大约CPU时间的0.1%,I / O等待将是主要因素。

So I'm posting this more like an example how things can be done in different way. 因此,我将其发布为一个示例,说明如何以不同的方式完成操作。

Edit: 编辑:

Also if you believe in the clib optimization, the: 另外,如果您相信clib优化,则:

        // Set bytes between first and last (simple 0xFF - all bits set)
        while (++firstClusterByte < lastClusterByte)
            clustersSet[firstClusterByte] = bitmaskFull;

Can reuse clib memset magic: 可以重用clib memset魔术:

//#include <cstring>
    // Set bytes between first and last (simple 0xFF - all bits set)
    if (++firstClusterByte < lastClusterByte)
        memset(clustersSet, bitmaskFull, (lastClusterByte - firstClusterByte));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM