【发布时间】:2011-01-25 23:58:18
【问题描述】:
我创建了一个函数来设置或清除 DWORD 中的特定位数。我的功能有效。我不需要帮助让它工作。但是,我想知道我选择的方法是否是最快的方法。
我很难解释这是如何工作的。有两个包含 DWORD 的数组,它们在 DWORD 的左侧和右侧填充了位(所有二进制 1)。它制作了一个掩码,除了我要设置或清除的位之外的所有位都已填充,然后使用基于该掩码的按位运算符设置它们。对于这样一个简单的任务,它似乎相当复杂,但它似乎是我能想到的最快方法。这比一点一点设置要快得多。
static DWORD __dwFilledBitsRight[] = {
0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
};
static DWORD __dwFilledBitsLeft[] = {
0x0, 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF
};
// nStartBitFromLeft must be between 1 and 32...
// 1 is the bit farthest to the left (actual bit 31)
// 32 is the bit farthest to the right (actual bit 0)
inline void __FillDWORDBits(DWORD *p, int nStartBitFromLeft, int nBits, BOOL bSet)
{
DWORD dwLeftMask = __dwFilledBitsLeft[nStartBitFromLeft - 1]; // Mask for data on the left of the bits we want
DWORD dwRightMask = __dwFilledBitsRight[33 - (nStartBitFromLeft + nBits)]; // Mask for data on the right of the bits we want
DWORD dwBitMask = ~(dwLeftMask | dwRightMask); // Mask for the bits we want
DWORD dwOriginal = *p;
if(bSet) *p = (dwOriginal & dwLeftMask) | (dwOriginal & dwRightMask) | (0xFFFFFFFF & dwBitMask);
else *p = (dwOriginal & dwLeftMask) | (dwOriginal & dwRightMask) | 0;
}
【问题讨论】:
-
我也是这么想的……但我的目标平台是i386+
-
就个人而言,当我觉得有些事情很难向其他人解释时,我会将其视为一个警告信号。 :-) 您可能应该对您的代码进行基准测试,并与设置进行比较(如果您还没有的话)。您是否尝试过使用联合?
-
是的,我不相信我在 Windows 中使用时钟滴答的基准测试...但是根据指令的数量,逐位设置在整个迭代过程中会有更多的指令。
-
作为旁注,您的
__Fi...名称给出了未定义的行为(以下划线开头的名称后跟另一个下划线或大写字母保留用于实现)。就个人而言,我会将其分为两个函数,fill_bits和clear_bits。将bool作为参数传递通常是一个错误——如果您坚持使用这种结构,请使用change_bits之类的内容并传递enum { CLEAR, FILL};。作为参数 - 但单独的功能会更好,IMO。 -
有趣...我通常对这些函数使用两个下划线,这样我可以在我的函数列表中更快地找到它们...我正在努力理解您在这里所说的...我不喜欢 unix 风格的命名约定(即lower_lower())。就我个人而言,我认为它们使我的程序可读性降低,而且更加神秘。
标签: c bit-fields bitflags