中
这是关于K&R书第二版的练习2-6。请读者:
编写函数集位(x,p,n,y),返回x,从位置p开始到y的最右边的n位,而其他位不变。
以下是每个参数的非正式操作:
#include <stdio.h>
//setbits: returns x with n bits that begin at p set to the rightmost n bits of y
//informally: "chop" n bits right->left from y, insert on x at position p
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
return ((~(~0 << n) & y) << p) | ((~(~(~0 << n) << p)) & x);
}
int main(void) {
// Example test cases:
// First scenario:
// x = 100 -> 0110 0100
// y = 5 -> 0000 0101
// p = 4
// n = 3
// Expected outcome: 0101 0100 (84)
// Second scenario:
// x = 94 -> 0101 1110
// y = 195 -> 1100 0011
// p = 0
// n = 3
// Expected outcome: 0101 1011 (91)
// Third scenario:
// x = 94 -> 0101 1110
// y = 195 -> 1100 0011
// p = 6
// n = 4
// Expected outcome: 1101 1110 (222)
printf("%d\n", setbits(100, 4, 3, 5));
printf("%d\n", setbits(94, 0, 3, 195));
printf("%d\n", setbits(94, 6, 4, 195));
return 0;
}
点击获取全尺寸图像
发布于 2018-06-12 22:09:55
将1移到符号位置是未定义的行为(UB)。(C11§6.5.7 4)相反,使用无符号类型。0是一个int常数。0u是一个unsigned常数。
// return ((~(~0 << n) & y) << p) | ((~(~(~0 << n) << p)) & x);
return ((~(~0u << n) & y) << p) | ((~(~(~0u << n) << p)) & x);代码清晰,让编译器形成最优的代码。
// return ((~(~0u << n) & y) << p) | ((~(~(~0u << n) << p)) & x);
unsigned new_mask = ~(~0u << n);
unsigned old_mask = ~(mask << p);
return ((new_mask & y) << p) | (old_mask & x);带有"%d"的unsigned应该会引发编译器警告/注释。启用所有编译器警告,以避免如此容易识别的问题。
// printf("%d\n", setbits(100, 4, 3, 5));
printf("%u\n", setbits(100, 4, 3, 5));对于此任务,使用"%4x"将比使用"%u"提供更多的信息。
“我使用了许多不同的场景进行了测试,这段代码已经通过了所有这些方案。”->用UINT_MAX, UINT_MAX-1, 1, 0进行测试将有助于检查函数的“角”。
仅限于0 <= p < bit_width和0 <= n < bit_width的代码。由于代码无法处理所有可能的输入值,说明限制会减少不正确的使用。
为所有可能的输入定义行为的优点是不需要列出限制,但可能不需要功能性的(以及代码过载)。
仍然很好的张贴限制。
在最后一点上,也许稍微重写一下代码是为了让人很容易地期望n == bit_width是有效的。
// This assumes no padding in `unsigned`
#define UINT_BIT_WIDTH (CHAR_BIT * sizeof(unsigned))
unsigned setbits(unsigned x, int p, int n, unsigned y) {
unsigned new_mask = n >= UINT_BIT_WIDTH ? UINT_MAX : ~(~0u << n);
...
}https://codereview.stackexchange.com/questions/196242
复制相似问题