我正在开发一个处理使用哈希的文件的程序。数据分为长度为0x1000的块。我需要计算具有一定起始和结束偏移量覆盖的线段的块数。
例如,如果段的起始偏移为0x2000,结束为0x3523,则意味着它将占用两个块:0x2000和0x3000。它不会占用数据块中的完整0x2000字节,但是在其内部时,它被视为“占用了一块”。我首先想到的是:
( ( EndingOffset - StartingOffset ) + 0xFFF ) >> 0xC
这等效于
Math.Ceil((EndingOffset - StartingOffset) / 0x1000)
,但是我是按位运算符的新手,喜欢与他们合作的挑战。无论如何,逻辑都是有缺陷的,例如,这就是我的情况,如果起始偏移为0x3D8A,结束偏移为0x671D,则两者之间的差为0x2993。取整为0x3000或三个块。该段实际上占用了四个,分别为0x3000、0x4000、0x5000和0x6000。所以我的下一班火车,很不幸的是我的下一班火车,是找到该分段所在的第一个程序段的偏移量与该分段不在的第一个程序块的偏移量之间的差。
使用0x3D8A和0x671D,这使我进入
(0x7000 - 0x3000) >> 0xC
,它成功产生了正确数量的块4。我编写它的方式是我要改进的,这是:BlockSize = ((((OffsetEnd + 0xFFF) >> 12) + 1) - ((OffsetStart + 0xFFF) >> 12));
我知道我已经使一个简单的问题复杂化了,但是我无法全神贯注于如何更好地编写它。
编辑:这很尴尬。我不知道我是怎么来的
(((OffsetEnd + 0xFFF) >> 12) - (OffsetStart >> 12));
仍然似乎还不完整。
编辑2:对不起,忘了提及结束偏移量是排他的,不是排他的,并且是该段最后一个字节之后的位置,表示:
(((OffsetEnd - 1 + 0xFFF) >> 12) - (OffsetStart >> 12));
编辑3:离开Kerek的答案,我得出以下结论:
BlockSize = 1 + (offsetEnd - 1 >> 12) - (offsetStart >> 12);
..或,从0开始计数,
BlockSize = (offsetEnd - 1 >> 12) - (offsetStart >> 12);
编辑4:忘记从零开始计数,我坚持:
BlockSize = 1 + (offsetEnd - 1 >> 12) - (offsetStart >> 12);
最佳答案
假设您的数据范围指定为[start, end),这非常简单:
unsigned int start_block = start_offset / 0x1000;
unsigned int end_block = end_offset / 0x1000;
unsigned int number_of_blocks = end_block - start_block + (end_offset > start_offset && end_offset % 0x1000 > 0 ? 1 : 0);
我想,
/ 0x1000
的位摆弄等效项是>> 12
。您的数据将占据块范围[start_block,end_block)。请注意,块0为[0x0000,0x1000),块1为[0x1000,0x2000)等。
正如@Ron所指出的,您将需要一个条件来区分最后一个(“过去”)块是否为空,并在后一种情况下将块计数加1。