https://www.cnblogs.com/machao/p/8397961.html
我发现,当把这些题做完之后对本章知识的理解才算有点小进步。下边的答案主要参考了这两个网站:
- http://blog.csdn.net/zhanyu1990/article/details/24936663
- https://dreamanddead.gitbooks.io/csapp-3e-solutions/chapter2
辅助函数:
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
unsigned f2u(float f)
{
return *(unsigned *)&f;
}
float u2f(unsigned u)
{
return *(float *)&u;
}
2.58
原理是把指向一个int类型的指针强行改为指向char类型,一般来说一个char占8位,这就能判断出来取出的值是否大于1
int is_little_endian(){
int a = 1;
return *((char*)&a);
}
2.59
这个比较简单,主要考察如何获取某些位。
(x&0xFF) | (y&~0xFF)
2.60
i << 3
表示i * 2^3
, 其原理是找出需要替换的那些位,然后将其替换掉就行了。
unsigned replace_byte(unsigned x, unsigned char b, int i)
{
return (x & ~(0xFF<<(i<<3))) | (b << (i<<3));
}
位级整数编码规则
2.61
下边的内容跟书的题目有关系,需要根据实际情况。
A(!~x) // 比较简单,不解释
B(!x) // 同上
C(!~(x | (~0xFF))) // x的最低有效字节中的位都等于1
D(!(x >> ((sizeof(int) - 1) << 3))) // x的最高有效字节中的位都等于0
2.62
这个题我觉得在使用补码表示整数的机器上是没啥问题的
#include <stdio.h>
int int_shifts_are_arithmetic() {
int i = -1;
return (i >> 1) == -1;
}
int main(void) {
printf("%d", int_shifts_are_arithmetic());
}
2.63
#include <stdio.h>
unsigned srl(unsigned x, int k) {
int xsrl = (int)x >> k;
int w = 8 * sizeof(int);
unsigned z = 2 << (w - k -1);
return (z - 1) & xsrl;
}
int sra(int x, int k) {
int xsra = (unsigned)x >> k;
int w = sizeof(int) << 3;
unsigned z = 1 << (w - k - 1);
unsigned mask = z - 1;
unsigned right = xsra & mask;
unsigned left = ~mask & (~(z & xsra) + z);
return left | right;
}
int main(void) {
unsigned t1 = srl(100, 2);
unsigned t2 = (unsigned)100 >> 2;
printf("%d----%d \n", t1, t2);
int t3 = sra(100, 2);
int t4 = 100 >> 2;
printf("%d----%d \n", t3, t4);
int t5 = sra(-100, 2);
int t6 = -100 >> 2;
printf("%d----%d \n", t5, t6);
}
2.64
// 该题目要求,只要奇数位有1,就返回1,否则返回0
#include <stdio.h>
/* Return 1 when any odd bit of x equals 1, 0 otherwise.
Assume w = 32.
*/
int any_odd_one(unsigned x) {
return !!(x & 0x55555555);
}
int main(void) {
int result = any_odd_one((unsigned)5);
printf("The result of 5: %d \n", result);
int result1 = any_odd_one((unsigned)2);
printf("The result of 2: %d \n", result1);
}
2.65
// 该题目要求,只要二进制书中1的个数为奇数,就返回1,否则返回0
#include <stdio.h>
/* Return 1 when x contains an odd nuimber of 1s, 0 otherwise.
Assume w = 32.
*/
int odd_ones(unsigned x) {
// 这是第一层的处理,对某一位i而言,通过右移了一位,我们就获取到了i前边的那一位,把他们异或后,
// 得到的位的值为0或者1,1就表示和前边的一位中有奇数个1,0表示有偶数个1.
x ^= (x >> 1);
// 经过上边的处理后呢,x中每一位的值的意义就不同了,他表示该位和它前边的位1的个数是奇数还是偶数
// 此时我们再右移2位,就获得了i前边的前边的值j,这个值j表示j和前边一位1的个数是奇数还是偶数
// 异或后,的值就便是到j前边,一共四位1的个数是奇数还是偶数
x ^= (x >> 2);
// 后面的都是按照上边的原理依次类推的
x ^= (x >> 4);
x ^= (x >> 8);
x ^= (x >> 16);
return x & 1;
}
int main(void) {
int result = odd_ones((unsigned)5);
printf("The result of 5: %d \n", result);
int result1 = odd_ones((unsigned)7);
printf("The result of 3: %d \n", result1);
}
2.66
#include <stdio.h>
#include <assert.h>
// 1. 先使用或加位移让第一个1的后边都是1
// 2. 然后取非后右移一位后,最右边的1就是我们想要的掩码
// 3. 由于上边得到的那个1就是原值中的第一个1的位置,因此&上原值就清空了1前边的位
int leftmost_one(unsigned x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x & (~x >> 1);
}
int main(void) {
assert(leftmost_one(0xff00) == 0x8000);
assert(leftmost_one(0x6600) == 0x4000);
return 0;
}
2.67
#include <stdio.h>
#include <assert.h>
int int_size_is_32() {
int set_msb = 1 << 31;
int beyond_msb = set_msb << 1;
return set_msb && !beyond_msb;
}
int int_size_is_32_for_16bit() {
int set_msb = 1 << 15 << 15 << 1;
int beyond_msb = set_msb << 1;
return set_msb && !beyond_msb;
}
int main(void) {
printf("1: %lu \n", sizeof(1));
printf("32: %d \n", int_size_is_32());
printf("16: %d \n", int_size_is_32_for_16bit());
}
2.68
#include <stdio.h>
#include <assert.h>
int lower_one_mask(int n) {
int w = sizeof(int) << 3;
return (unsigned)-1 >> (w - n);
}
int main(void) {
assert(lower_one_mask(6) == 0x3F);
assert(lower_one_mask(17) == 0x1FFFF);
assert(lower_one_mask(32) == 0xFFFFFFFF);
return 0;
}
2.69
#include <stdio.h>
#include <assert.h>
unsigned rotate_left(unsigned x, int n) {
int w = sizeof(int) << 3;
unsigned t = x << n;
unsigned t1 = x >> (w - n - 1) >> 1;
return t | t1;
}
int main(void) {
assert(rotate_left(0x12345678, 4) == 0x23456781);
assert(rotate_left(0x12345678, 20) == 0x67812345);
assert(rotate_left(0x12345678, 0) == 0x12345678);
return 0;
}
2.70
#include <stdio.h>
#include <assert.h>
// 如果x的二进制可以用n位表示就返回1,
/*
* Assume w = 8, n = 3
* if x > 0
* 0b00000110 is ok, 0b00001010 is not
* first w-n bits must be 0
* if x < 0
* 0b11111100 is ok, 0b10111100 is not, and 0b11111000 is not yet
* first w-n+1 bits must be 1
*/
int fits_bits(int x, int n) {
int w = sizeof(int) << 3;
x >>= n - 1;
/*
* !(x >> 1) 用于判断x大于0的情况
* !~x 用于判断x小于0的情况
*/
return !(x >> 1) || !~x;
}
int main(void) {