题目:假设我们将一个w位的字中的字节从0(最低位)到w/8-1(最高位)编号。写出下面C函数的代码,它会返回一个无符号值,其中参数x的字节i被替换成字节b:
unsigned replace_byte(unsigned x,int i,unsigned char b);
以下示例,说明了这个函数该如何工作:
replace_byte(0x12345678,2,0xAB)-->0x12AB5678
replace_byte(0x12345678,0,0xAB)-->0x123456AB
函数条件略.........
答题思路
按照示例中的数字规则,当i=2,b=0xAB时,要将0x12345678=>0x12AB5678,首先认为0x12AB5678由 0x12AB0000^0x5678而来,再0x12AB0000由0x1200^0xAB而来,0x1200由0x1234&(~0xFF)来,而0x1234与0x5678均可通过0x12345678根据i进行位移运算获得,根据此思路写下如下代码:
#include <stdio.h>
unsigned repace_byte(unsigned x,int i,unsigned char b){
int vv=sizeof(int);
printf("((vv-i)<<3) %d \n",((vv-i)<<3));
unsigned d=x<<((vv-i)<<3);
printf("d %.2x \n",d);
d=d>>((vv-i)<<3); //获取i后字节;
printf("d2 %.2x \n",d);
unsigned c=x>>(i<<3); //获取i字节之前;
printf("c %.2x \n",c);
c=c&(~0xFF);
printf("c2 %.2x \n",c);
c=c^b;
printf("c^b %.2x \n",c);
c=c<<((i)<<3);
printf("c3 %.2x \n",c);
c=c^d;
return c;
}
int main()
{
/* 我的第一个 C 程序 */
printf("Hello, World! %.2x \n",repace_byte(0x12345678,2,0xAB));
return 0;
}
经过运行,当i=1、2、3时均可取得正确结果,但是i=0时结果并不正确。经过确认,unsigned的长度位32位,左移32位将获得它自身,与期望左移32位不相符.
。。。纠结了一晚怎么在i=0的时候将d变成0!
Later
参考大佬的答案http://t.csdn.cn/cJqW4
大佬的思路与官方答案思路一样:是将b左移8*i位,如i=0,则不移动,则b移动后为0xAB,然后通过表达式x&(~(0xFF << i * 8))将x变成0x12345600,如果i=1,x=0x12340078,b=0xAB00。最后x|b可获得正确结果。
反思:此题隐约意识到会使用到0xFF常量,事实上也用到了,但是对位移运算的掌握程度不牢固。