此问题的一般解决方案是使用& 运算符和适当的掩码清除目标范围中的位,并设置来自第二个变量的位,如果不能断言没有设置其他位,则适当移位并可能被掩码:
v1 = (v1 & ~(0xF << 2)) | ((v2 & 0xF) << 2);
如果您知道v2 的所有位都设置在目标范围内,则可以简化为:
v1 = v1 | (0xF << 2);
但是请注意(v1 & ~(0xF << 2)) 使用int 算术,如果掩码类型大于int,它将扩展掩码到v1 的宽度。但是,如果目标包含int 类型的符号位,则将1 位移动到该位置是未定义的行为。使用显式常量也不行,因为它的类型为unsigned int,如果v1 的类型大于int,则将其扩展为v1 的类型也会掩盖v1 的高位。例如:
/* replacing bits 31,30,29,28 */
long long v1 = 0x987654321;
int v2 = 0xF;
v1 = (v1 & ~(0xF << 28)) | ((v2 & 0xF) << 28);
// v1 is now 0x9F7654321 but really undefined behavior
v1 = (v1 & ~0xF0000000) | ((v2 & 0xF) << 28);
// v1 is now 0xF7654321 instead of 0x9F7654321
如果v2 的类型小于v1 的类型并且必须移动到其自身长度之外,则会出现类似的问题。
一种更安全的方法是使用带有与v1 类型匹配的尾随类型标记的常量,但如果必须将一个位移入long long 类型的符号位,这仍然不起作用:
v1 = (v1 & ~(0xFLL << 60)) | ((v2 & 0xFLL) << 60); // undefined behavior
一般的解决方案是使用unsigned long long 常量:
v1 = (v1 & ~(0xFULL << 28)) | ((v2 & 0xFULL) << 28);
过时的非 2 的补码体系结构的行为并非微不足道,将被忽略。