2.60

看到这个体题我的思路如下:
- 先将x中需要替换的部分全都改成0
- 创建一个临时变量
tmp = 0x000000FF - 通过向左位移运算右侧补0,将FF字节移到指定的位置
- tmp取反,此时
tmp = 0xFF00FFFF - 通过且运算将x中对应字节抹零
- 创建一个临时变量
- 将b转化为unsigned类型,并且左移,让有效数据位与x抹零的部分对其
- 通过或预算将b中的有效数据位赋给x抹零的片段
#include <stdio.h>
unsigned replace_byte (unsigned x,int i,unsigned char b)
{
//先将x的需要替换的部分全都抹零
unsigned tmp = (0x000000FF);
tmp = tmp << i*8;
tmp = ~tmp;
x = x & tmp;
//再把b的数据转移的合适的位置上通过或预算放到x中
x = x |((unsigned)b) << i*8;
return x;
}
int main()
{
unsigned x = 0x12345678; //以16进制初始化x
int i = 2;
unsigned char b = 0xAB; //以16进制初始化b
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是奇数还是偶数
根据以上思路给出代码如下:
#include<stdio.h>
int odd_ones(unsigned x)
{
//合并每相邻2位的1的个数
x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
//再合并每相邻4位1的个数
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
//合并每相邻8位的1的个数
x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
//合并每相邻16位的1的个数
x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
//得到32位的1的个数
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位
#include<stdio.h>
int bad_int_sizeis_32(){
int set_msb = 1 << 31 ; //左移31位,将1移到符号位上
int beyond_msb = set_msb >> 31; // 算术右移31位,检查符号位是否保持不变
return beyond_msb == -1; //确保机器位数等于32
}
int main()
{
printf("%d\n", bad_int_sizeis_32());
return 0;
}
C). 当1被左移到符号位时,x会从正数变为复数,我们根据这一条件进行判断,写出代码:
#include<stdio.h>
int bad_int_sizeis_32(){
int x = 1;
int count = 1;
// 逐步左移,直到最高位被设置
while (x > 0) {
x <<= 1;
count++;
}
// 如果位宽为32,则返回1,否则返回0
return count == 32;
}
int main()
{
printf("%d\n", bad_int_sizeis_32());
return 0;
}
2.68

#include<stdio.h>
int lower_one_mask(int n)
{
int x = -2;
x = x << n-1; // 使用 n & 31 确保移位位数在 0 到 31 之间
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位的情况。
结果如下:
