我喜欢这两种解决方案。这是我想到的另一种方式(可能不是更好)。
((~((unsigned int)0) << k) >> (k + n)) << n
编辑:
我以前的版本中有一个错误(它没有 unsigned int 强制转换)。问题是~0 >> n在前面加了1而不是0。
是的,这种方法有一个很大的缺点。它假定您知道默认整数类型的位数,或者换句话说,它假定您确实知道 k,而其他解决方案与 k 无关。这使得我的版本不那么便携,或者至少更难移植。 (它还使用了 3 次移位,以及加法和按位否定运算符,这是两个额外的操作。)
因此,您最好使用其他示例之一。
这是一个由 Jonathan Leffler 完成的小测试应用程序,用于比较和验证不同解决方案的输出:
#include <stdio.h>
#include <limits.h>
enum { ULONG_BITS = (sizeof(unsigned long) * CHAR_BIT) };
static unsigned long set_mask_1(int k, int m, int n)
{
return ~(~0 << m) << n;
}
static unsigned long set_mask_2(int k, int m, int n)
{
return ((1 << m) - 1) << n;
}
static unsigned long set_mask_3(int k, int m, int n)
{
return ((~((unsigned long)0) << k) >> (k + n)) << n;
}
static int test_cases[][2] =
{
{ 1, 0 },
{ 1, 1 },
{ 1, 2 },
{ 1, 3 },
{ 2, 1 },
{ 2, 2 },
{ 2, 3 },
{ 3, 4 },
{ 3, 5 },
};
int main(void)
{
size_t i;
for (i = 0; i < 9; i++)
{
int m = test_cases[i][0];
int n = test_cases[i][1];
int k = ULONG_BITS - (m + n);
printf("%d/%d/%d = 0x%08lX = 0x%08lX = 0x%08lX\n", k, m, n,
set_mask_1(k, m, n),
set_mask_2(k, m, n),
set_mask_3(k, m, n));
}
return 0;
}