将数组右移 1
Shift an array to the right with 1
我试图用一些二进制 1 将一个 unsigned char 数组右移。
示例:0000 0000 | 0000 1111 我移动 8 次会给我 0000 1111 | 1111 1111(二进制左移)
所以在我的数组中我会得到:{0x0F, 0x00, 0x00, 0x00} => {0xFF, 0x0F, 0x00, 0x00}(数组右移)
我目前使用函数 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
如您所见,我成功地逐个元素地移动了我的数组,但我不知道如何将 0 替换为 1。我想使用 memset 可以工作,但我无法正确使用它。
感谢您的帮助!
编辑:这是为了填充 exFAT 磁盘的位图区域。当你在磁盘中写一个簇时,你必须将位图的相应位设置为1(第一个簇是第一个位,第二个簇是第二个位,...)。
新格式化的驱动器将在位图的第一个字节中包含 0x0F,因此建议的示例符合我的需要,如果我写 8 个簇,我需要将值移动 8 次并用 1 填充它。
在代码中,我写了 4 个簇,需要将值移动 4 位,但它移动了 4 个字节。
将问题设为已解决,却无法如愿。我不需要移动数组的位,而是需要分别移动数组的每个字节。
将问题设置为已解决,无法按我的意愿进行。我需要分别编辑数组的每一位,而不是移动数组的位。
下面是代码,如果它可以帮助其他人的话:
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 是我要在位图中添加的簇数
firstCluster 是我可以写入数据的第一个集群(使用了 4 个集群:0、1、2 和 3,所以我从 4 开始)。
bitIndex 用于修改数组字节中的右位 => 每次递增。
byteIndex 用于修改数组的右字节 => 每次该位等于 7 时递增。
如果您出于性能原因不想使用 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
不幸的是,我没有分析任何版本(你的和我的),所以我不知道在这两种情况下优化的 C 编译器输出的质量如何。在蹩脚的 C 编译器和 386-586 处理器的时代,我的版本会快得多。对于现代 C 编译器,LUT 的使用可能会适得其反,但除非有人通过一些分析结果证明我错了,否则我仍然认为我的版本效率更高。
也就是说,由于写入文件系统可能在此之前涉及,即使使用您的变体,设置位也可能需要大约 %0.1 的 CPU 时间,I/O 等待将是主要因素.
所以我发布这个更像是一个如何以不同方式完成事情的例子。
编辑:
此外,如果您相信 clib 优化,则:
// Set bytes between first and last (simple 0xFF - all bits set)
while (++firstClusterByte < lastClusterByte)
clustersSet[firstClusterByte] = bitmaskFull;
可以重用 clib memset
魔法:
//#include <cstring>
// Set bytes between first and last (simple 0xFF - all bits set)
if (++firstClusterByte < lastClusterByte)
memset(clustersSet, bitmaskFull, (lastClusterByte - firstClusterByte));
我试图用一些二进制 1 将一个 unsigned char 数组右移。
示例:0000 0000 | 0000 1111 我移动 8 次会给我 0000 1111 | 1111 1111(二进制左移)
所以在我的数组中我会得到:{0x0F, 0x00, 0x00, 0x00} => {0xFF, 0x0F, 0x00, 0x00}(数组右移)
我目前使用函数 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
如您所见,我成功地逐个元素地移动了我的数组,但我不知道如何将 0 替换为 1。我想使用 memset 可以工作,但我无法正确使用它。
感谢您的帮助!
编辑:这是为了填充 exFAT 磁盘的位图区域。当你在磁盘中写一个簇时,你必须将位图的相应位设置为1(第一个簇是第一个位,第二个簇是第二个位,...)。
新格式化的驱动器将在位图的第一个字节中包含 0x0F,因此建议的示例符合我的需要,如果我写 8 个簇,我需要将值移动 8 次并用 1 填充它。
在代码中,我写了 4 个簇,需要将值移动 4 位,但它移动了 4 个字节。
将问题设为已解决,却无法如愿。我不需要移动数组的位,而是需要分别移动数组的每个字节。
将问题设置为已解决,无法按我的意愿进行。我需要分别编辑数组的每一位,而不是移动数组的位。
下面是代码,如果它可以帮助其他人的话:
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 是我要在位图中添加的簇数 firstCluster 是我可以写入数据的第一个集群(使用了 4 个集群:0、1、2 和 3,所以我从 4 开始)。 bitIndex 用于修改数组字节中的右位 => 每次递增。 byteIndex 用于修改数组的右字节 => 每次该位等于 7 时递增。
如果您出于性能原因不想使用 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
不幸的是,我没有分析任何版本(你的和我的),所以我不知道在这两种情况下优化的 C 编译器输出的质量如何。在蹩脚的 C 编译器和 386-586 处理器的时代,我的版本会快得多。对于现代 C 编译器,LUT 的使用可能会适得其反,但除非有人通过一些分析结果证明我错了,否则我仍然认为我的版本效率更高。
也就是说,由于写入文件系统可能在此之前涉及,即使使用您的变体,设置位也可能需要大约 %0.1 的 CPU 时间,I/O 等待将是主要因素.
所以我发布这个更像是一个如何以不同方式完成事情的例子。
编辑:
此外,如果您相信 clib 优化,则:
// Set bytes between first and last (simple 0xFF - all bits set)
while (++firstClusterByte < lastClusterByte)
clustersSet[firstClusterByte] = bitmaskFull;
可以重用 clib memset
魔法:
//#include <cstring>
// Set bytes between first and last (simple 0xFF - all bits set)
if (++firstClusterByte < lastClusterByte)
memset(clustersSet, bitmaskFull, (lastClusterByte - firstClusterByte));