2.60

看到这个体题我的思路如下:
- 先将x中需要替换的部分全都改成0
- 创建一个临时变量
tmp = 0x000000FF
- 通过向左位移运算右侧补0,将FF字节移到指定的位置
- tmp取反,此时
tmp = 0xFF00FFFF
- 通过且运算将x中对应字节抹零
- 将b转化为unsigned类型,并且左移,让有效数据位与x抹零的部分对其
- 通过或预算将b中的有效数据位赋给x抹零的片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <stdio.h>
unsigned replace_byte (unsigned x,int i,unsigned char b) { unsigned tmp = (0x000000FF); tmp = tmp << i*8; tmp = ~tmp; x = x & tmp; x = x |((unsigned)b) << i*8; return x; }
int main() { unsigned x = 0x12345678; int i = 2; unsigned char b = 0xAB; printf("replace_byte(0x%08X,%d,0x%02X) = 0x%08X\n",x,i,b,replace_byte(x,i,b)); return 0; }
|
代码运行结果如下:


2.65

这道题我们先思考一下:
- 要计算32位中一的个数,我们可以分别计算前16位的1的个数+后16位1的个数。
- 计算16位1的个数,可以同样分为8+8
- 再次划分,我们分为4+4
- 然后我们分为2+2
- 最后我们分为1+1
这样我们只需要先计算每位中1的个数,再逐级倒退,得到32 位中1的个数
好这样针对每两位中1的个数我们就可以如下实现:
我们假设一个两位的二进制数为x
其中的1的个数为:(x & 1) + ((x>>1) & 1) //将x的两位分别和1进行与运算,结果相加得到1的个数
然后我们再计算每4位中1的个数:(x & 11) + ((x>>2) &11) //4位数中前两位中1的个数
+后两位1的个数
接下来同理得到8位中1的个数:(x & 1111) + ((x>>4) & 1111)
同理得16位:(x & 11111111) + ((x>>8) & 11111111)
最后我们就可以得到32位:(x & 1111111111111111) + ((x>>16) + 1111111111111111)
最后我们通过x & 1 来判断x是奇数还是偶数
根据以上思路给出代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<stdio.h>
int odd_ones(unsigned x) { x = (x & 0x55555555) + ((x >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF); return x & 1 ; } int main() { int x = 0x10101011; printf("%d\n", odd_ones(x)); return 0; }
|
程序运行结果如下:x = 0x10101011

2.67

我们先来分析报错:left shift count >= width of type
左移位数大于或等于类型的宽度
A).代码第6行 1 << 32
如果在32位机器上运行,将1左移32位会让1被移到第33位上,但33位并不存在,超出了类型的宽度。
B).当机器位数>= 32时,我们可以位操作的范围是:0~31。并且题目右移为算数右移,那么我们可以通过将 1 << 31
移至符号位,再通过算数右移,此时通过判断beyond的大小来判断机器int是否为32位
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<stdio.h>
int bad_int_sizeis_32(){ int set_msb = 1 << 31 ; int beyond_msb = set_msb >> 31; return beyond_msb == -1; }
int main() { printf("%d\n", bad_int_sizeis_32()); return 0; }
|
C). 当1被左移到符号位时,x会从正数变为复数,我们根据这一条件进行判断,写出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<stdio.h>
int bad_int_sizeis_32(){ int x = 1; int count = 1;
while (x > 0) { x <<= 1; count++; } return count == 32; }
int main() { printf("%d\n", bad_int_sizeis_32()); return 0; }
|
2.68

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<stdio.h>
int lower_one_mask(int n) { int x = -2; x = x << n-1; x = ~x; return x; } int main() { int n = 1; while(n!=-1) { printf("请输入n的值:"); scanf("%d",&n); printf("%X\n",lower_one_mask(n)); } return 0; }
|
n>=1 ,所以令x = -2,让 x 每左移n-1位,最后给x取反,就能得到做多1的n bits 的数,就能避免一次位移32位的情况。
结果如下:
