注意点
- 计算机一般使用8位的块或者字节作为最小的可寻址的单位。而不是直接对位进行编码。
- 虚拟存储器 :一个字节数组
- 虚拟地址空间:所有可能的地址
- 一个指针的值都是 存储块的第一个字节的虚拟地址。指针的类型是由编译器来维护的,具体的机器代码却没有关于数据类型的信息。
- C语言里面 0x|0X aA
- 字长,虚拟空间是以一个字来编码的,所以字的大小决定了虚拟空间的大小。
- 多字节对象存储为连续的,地址为字节中最小的地址。
- 小端就是 最低位先放,大端就是 最高位先放
- 十进制数x的ASCII码就是0x3x
- ASCII具有更加好的平台独立性,字节顺序无关大小端。
- 无符号数字截断到k位就是等价于x mod 2^k,补码的话还要加上2^n.
- 负数计算,如果是无符号数的话: x + y := 0 mod 2^m也就是-0 = 0,x = 2^m - x。如果是补码的话,-INT_MIN=INT_MIN,其他一样。1
- 浮点数从 0 000 0000 不断递增, 直到0 111 0000停止都是比较正常的数字后面都是NaN. 对于 0 000 * 系列数字 阶码等于下一组数的阶码也就是 1−(2k−1−1)=2−2k−1 数的值就是数的值。 从下一组开始就是阶码不为0开始,阶码等于x-bias=x-(2^{k-1}-1),数的值等于1+数的值。
- 向偶数舍入,如果是0.5那么就是向偶数前进,其他就取最近的了。
练习题
2.1
A. 0x39A7F8 = 0011 1001 1010 0111 1111 1000
B. 1100 1001 0111 1011 = 0xC98B ->0xC97B
C. 0xD5E4C = 1100 0101 1110 0100 1010 -> 1101 0101 1110 0100 1100
D. 10 0110 1110 0111 1011 0101 = 0x26E7C5 -> 0x26E7B5
2.2
210=1024
,
2n=2k∗4+b=2b000(k个0)
220=1024∗1024=1000000+48000+576=1048576
n | 2n 10进制 | 2n 16进制 |
---|---|---|
9 | 512 | 0x200 |
19 | 524288 | 0x80000 |
14 | 16384 | 0x4000 |
16 | 65535 | 0x10000| |
17 | 131072 | 0x10000->0x20000 |
5 | 32 | 0x10->0x20 |
7 | 128 | 0x80 |
2.3
167 = 16 * 10 + 7
十进制 | 二进制 | 十六进制 |
---|---|---|
0 | 0000 0000 | 0x00 |
167 | 1010 0111 | 0xA7 |
62 | 0011 1100-> 0011 1110 | 0x3D->0x3E |
188 | 1011 1100 | 0xCD->0xBC |
55 | 0011 0111 | 0x37 |
136 | 1000 1000 | 0x88 |
243 | 1111 0011 | 0xF3 |
82 | 0101 0010 | 0x52 |
172 | 1010 1100 | 0xAC |
231 | 1110 0111 | 0xE7 |
2.4
A. 0x503c + 0x8 = 0x5044
B. 0x503c - 0x40 = 0x4ffc
C. 0x503c + 64 = 0x503c +0x40 = 0x507c
D. 0x50ea-0x503c = 0xad->0xae
2.5
* | 小端 | 大端 |
---|---|---|
A | 21 | 87 |
B | 21 43 | 87 65 |
C | 21 43 65 | 87 65 43 |
2.6
- 0x00 35 91 41 = 0000 0000 0011 0101 1001 0001 0100 0001
- 0x4A 56 45 04 = 0100 1010 0101 0110 0100 0101 0000 0100
2.7
#include <stdio.h>
#include <cstring>
typedef unsigned char* byte_pointer;
void show_bytes(byte_pointer start,int len) {
for (int i = 0;i < len;i ++) {
printf(" %.2x",start[i]);
}
puts("");
}
void show_int(int x) {
show_bytes((byte_pointer)&x,sizeof(int));
}
void show_float(float x) {
show_bytes((byte_pointer)&x,sizeof(float));
}
void show_pointer(void *x) {
show_bytes((byte_pointer)&x,sizeof(void *));
}
int main() {
const char *s = "abcdef";
show_bytes((byte_pointer)s,strlen(s));
}
2.8
运算 | 结果 |
---|---|
a | [0110 1001] |
b | [0101 0101] |
~a | [1001 0110] |
~b | [1010 1010] |
a & b | [0100 0001] |
a | [0111 1101] |
a ^ b | [0011 1100] |
2.9
A.
- | - |
---|---|
111 | 011 |
110 | 010 |
101 | 001 |
100 | 000 |
B.
1. 001 | 010 = 011 蓝绿色
2. 110 & 011 = 010 绿色
3. 100 ^ 101 = 001 蓝色
2.10
#include <stdio.h>
#include <cstring>
#include <iostream>
using namespace std;
void inplace_swap(int *x,int *y) {
*y = *x ^ *y;
*x = *y ^ *x;
*y = *y ^ *x;
}
int main() {
int a = 1;
int b = 2;
inplace_swap(&a,&b);
cout <<a << " " << b << endl;
}
2.11
#include <stdio.h>
#include <cstring>
#include <iostream>
using namespace std;
void inplace_swap(int *x,int *y) {
*y = *x ^ *y;
*x = *y ^ *x;
*y = *y ^ *x;
}
void reverse_array(int a[],int cnt) {
int first, last;
for (first = 0,last = cnt-1;first **<=** last;first ++,last --) {
inplace_swap(&a[first],&a[last]);
}
for (int i = 0;i < cnt;i ++) {
cout << a[i] << " " ;
}
cout << endl;
}
int main() {
int a[5] = {1,2,3,4,5};
reverse_array(a,5);
}
2.12
A. x & 0xff
B. x ^ (~0xff)
C. x | 0xff
2.13
or: bis(x,y)
xor: LEARNED: bis(bic(x,y),bic(y,x))
因为bic(x,m) = x & ~m
x^y = (x & ~y) | (y & ~x)
2.14
x = 0x66,y = 0x39
x = 0110 0110
y = 0011 1001
表达式 | 值 |
---|---|
x & y | 0010 0000 |
x | y | 0111 1111 |
~x | ~y | 1101 1111 |
x & !y | 0100 0110 -> 0000 0000 |
x && y | 0x1 |
x || y | 0x1 |
!x || !y | 0x0 |
x && ~y | 0x0 |
2.15
x & ~y == 0 -> !(x ^ y)
2.16
十六进制 | 二进制 | 二进制 x<<3 | 十六进制x<<3 | 二进制x>>2 | 十六进制x>>2 | 二进制x>>2 | 十六进制x>>2 |
---|---|---|---|---|---|---|---|
0xC3 | 1100 0011 | 0001 1000 | 0x18 | 0011 0000 | 0x30 | 1111 0000 | 0xf0 |
0x75 | 0111 0101 | 1010 1000 | 0xA8 | 0001 1101 | 0x1D | 0001 1101 | 0x1D |
0x87 | 1000 0111 | 0011 1000 | 0x38 | 0010 0001 | 0x21 | 1110 0001 | 0xE1 |
0x66 | 0110 0110 | 0011 0000 | 0x30 | 0001 1001 | 0x19 | 0001 1001 | 0x19 |
2.17
十六进制 | 二进制 | 无符号数 | 补码 |
---|---|---|---|
0xE | 1110 | 14 | -2 |
0x0 | 0000 | 0 | 0 |
0x5 | 0101 | 5 | 5 |
0x8 | 1000 | 8 | -8 |
0xD | 1101 | 13 | -3 |
0xF | 1111 | 15 | -1 |
2.18
十六进制 | 二进制 |
---|---|
0x1b8 | 440 |
0x14 | 20 |
0xffff fe58 | 0x258 = -424 |
0xffff fe74 | 0x1e74 = 0x274 = 4 + 16*7-2*256 = 116-512 = -396 |
0x44 | 68 |
0xffff fec8 | 0x2c8 = 8 + 12*16 - 2 * 256=200 - 512 = -312 |
0x10 | 16 |
0xc | 12 |
0xffff feec | 0x2ec = 12 + 16*14 - 2 * 256 = -500 + 224 = -276 |
0x20 | 32 |
2.19
x | |
---|---|
-8 | 8 |
-3 | 13 |
-2 | 14 |
-1 | 15 |
0 | 0 |
5 | 5 |
2.20
2.21
表达式 | 类型 | 求值 |
---|---|---|
-2147483647-1==2147483648U | 无符号 | 1 |
-2147483647-1 < 2147483647 | 有符号 | 1 |
-2147483647-1U <2147483647 | 无符号 | 0 |
-2147483647-1<-2147483647 | 有符号 | 1 |
-2147483647-1U <-2147483647 | 无符号 | 1 |
2.22
2.23
w | fun1(w) | fun2(w) |
---|---|---|
0x00000076 | 0x00000076 | 0x00000076 |
0x87654321 | 0x00000021 | 0x00000021 |
0x000000C9 | 0x000000C9 | 0xFFFFFFC9 |
0xEDCBA987 | 0x00000087 | 0xFFFFFF87 |
2.24
从N位变成M位,如果是无符号数直接x mod 2^M
如果是有符号数先把他看成无符号数然后再变回有符号数
那就是(x + 2^N) % (2 ^ M) = x % 2 ^M.
所以无论是有符号数还是无符号数都先mod 2 ^M然后如果是有符号数再进行处理下
原始值 | 无符号 | 补码 |
---|---|---|
0 | 0 | 0 |
2 | 2 | 2 |
9 | 1 | 1 |
11 | 3 | 3 |
15 | 7 | -1 |
原始值 | 无符号 | 补码 |
---|---|---|
0 | 0 | 0 |
2 | 2 | 2 |
-7 | 9 | 1 |
-5 | 11 | 3 |
-1 | 15 | -1 |
2.25
错误原因: unsigned int - 1其实等于最大值了,然后i <= 最大值恒为真
float sum_elements(float a[],unsigned length) {
int i;
float result = 0;
for (i = 0,`i <= length-1`;i ++) {
result += a[i];
}
return result;
}
改成i < length
或者是int length
2.26
size_t strlen(const char* s);
int strlonger(char* s,char *t) {
reutnr strlen(s) - strlen(t) > 0;
}
改成strlen(s) > strlen(t)
2.27
2.28
十六进制 | 十进制 | 十进制 | 十六进制 |
---|---|---|---|
0 | 0 | 15 | F |
5 | 5 | 10 | A |
8 | 8 | 7 | 7 |
D | 13 | 2 | 2 |
F | 15 | 0 | 0 |
2.29
x | x+y | x+5y | 情况 | |
---|---|---|---|---|
10100 -12 | 10001 -15 | 100101 -27 | 00101 5 | 3 |
11000 -8 | 11000 -8 | 110000 -16 | 10000 -16 | 2 |
10111 -9 | 01000 8 | 11111 -1 | 1111 -1 | 2 |
00010 2 | 00101 5 | 00111 7 | 0111 7 | 2 |
01100 12 | 00100 4 | 010000 16 | 10000 -16 | 1 |
2.30
int tadd_ok(int x,int y) {
bool ok = true;
if(x > 0 && y > 0 && x + y `< -> <=` 0) ok = false;
if(x < 0 && y < 0 && x + y `> -> >=` 0) ok = false;
if(ok) return 1;
}
2.31
如果是正溢出,那么x+y = x +y -2^m
然后sum - x = x + y - 2^m -x = y - 2^m < 2^m-1
所以y-2^m = y-2^m+2^m=y
其他同理
2.32
当y时负数的时候,输入x-y x<0认为呢不会溢出,但是当y=INT_MIN的时候,-y=INT_MIN,所以返回溢出了。
int tadd_ok(int x,int y) {
bool ok = true;
if(x > 0 && y > 0 && x + y <= 0) ok = false;
if(x < 0 && y < 0 && x + y >= 0) ok = false;
if(ok) return 1;
return 0;
}
int main() {
int x = -2147483647 - 1;
cout << tadd_ok(-100,x) << endl;
}
2.33
十六进制 | 十进制 | 十进制 | 十六进制 |
---|---|---|---|
0 | 0 | 0 | 0 |
5 | 5 | 11 | B |
8 | 8 | 8 | 8 |
D | 13 | 3 | 3 |
F | 15 | 1 | 1 |
2.34
模式 | x | y | x*y | 截断的x*y |
---|---|---|---|---|
无符号 | 100 | 101 | 4*5=20 0001 1000 | 4 100 |
有符号 | 100 | 101 | -4*-3=12 0000 1100 | -4 100 |
无符号 | 010 | 111 | 2*7=14 0000 1110 | 6 110 |
有符号 | 010 | 111 | 2*-1=-2 110 | -2 110 |
无符号 | 110 | 110 | 6*6=36 0010 0100 | 4 100 |
有符号 | 110 | 110 | -2*-2=4 | -4 100 |
2.35 待完成
2.36
int tmult_ok(int x,int y) {
long long pll = (long long)x * y;
return pll == (int) pll;
}
2.37
malloc的传参数的时候会进行类型转换。
if(x != (unsigned)x)
2.38
2^k或者2^k+1
2.39
-(1<<m)
2.40
K | 移位 | 加减法 | 表达式 |
---|---|---|---|
6 | 2 | 1 | (x<<2)|(x<<1) |
31 | 1 | 1 | 32-1 (x<<5)-x |
-6 | 2 | 1 | -4-2 -(x<<2)-(x<<1) |
55 | 2 | 2 | 64-8-1 (x<<6)-(x<<3)-x |
2.41
第一个有n-m+1个
第二个有2个
所以如果n-m+1 < 2用第一个
如果n-m+1=2随便
其他用第二个
2.42
int div16(int x) {
int flag = `(x >> 31)` & 0xF; //这里产生一个字
return (x + flag) >> 4;
}
2.43
M=31,N=8
2.44
表达式 | 值 | 特例 |
---|---|---|
(x > 0) || (x - 1) < 0 | INT_MIN | |
(x & 7) != 7 || (x << 29 < 0) | TRUE | |
(x * x) >= 0 | (1<<15 | 1<<14) | |
x < 0 || -x <= 0 | TRUE | |
x > 0 || -x >= 0 | INT_MIN | |
x + y == ux + uy | TRUE | |
x * ~y +uy*ux == -x | TRUE |
x∗(−y−1)+uy∗ux=−x∗y−x+uy∗ux=−x
2.45
小数值 | 二进制表示 | 十进制表示 |
---|---|---|
18 | 0.001 | 0.125 |
34 | 0.11 | 0.75 |
2516 | 1.1001 | 1.5625 |
4316 | 10.1011 | 2.6875 |
98 | 1.001 | 1.125 |
478 | 101.111 | 5.875 |
5116 | 11.0011 | 1.1875 |
2.46
0.2 = 1/5 = 3/16 + 3/16^2+… =(3/16-0)/(1-1/16) = 1/5
A. 0…..1100 1100
B. 2^-20 * 1/10 = 9.54*10-8
C. 9.54*10-8*100*60*60*10 = 0.343
D. 0.343*2000 = 687
2.47
位 | e | E | 2E | f | M | 2E∗M | V | 十进制 |
---|---|---|---|---|---|---|---|---|
0 00 00 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 00 01 | 0 | 0 | 1 | 14 | 14 | 14 | 18 | 0.125 |
0 00 10 | 0 | 0 | 1 | 24 | 24 | 24 | 24 | 0.25 |
0 00 11 | 0 | 0 | 1 | 34 | 34 | 34 | 34 | 0.75 |
0 01 00 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 |
0 01 01 | 1 | 0 | 1 | 14 | 114 | 1 14 | 114 | 1.25 |
0 01 10 | 1 | 0 | 1 | 24 | 1 24 | 1 24 | 124 | 1.5 |
0 01 11 | 1 | 0 | 1 | 34 | 1 34 | 1 34 | 1 34 | 1.75 |
0 10 00 | 2 | 1 | 2 | 04 | 1 | 2 | 2 | 2 |
0 10 01 | 2 | 1 | 2 | 14 | 1 14 | 104 | 52 | 2.5 |
0 10 10 | 2 | 1 | 2 | 24 | 1 24 | 124 | 3 | 3 |
0 10 11 | 2 | 1 | 2 | 34 | 1 34 | 144 | 72 | 3.5 |
0 11 00 | inf | |||||||
0 11 01 | 不合法 | |||||||
0 11 10 | 不合法 | |||||||
0 11 11 | 不合法 |
2.48
3510493 = 11 0101 1001 0001 0100 0001 = 1.1 0101 1001 0001 0100 0001 * 2^21
21+127 = 128 + 20 = 1001 0100
0 1001 0100 1 0101 1001 0001 0100 0001 00
0100 1010 0101 0110 0100 0101 0000 0100
4A564504
2.49待完成
2.50
A. 10.010 10.0
B. 10.011 10.1
C. 10.110 11.0
D. 11.001 11.0
2.51
0.0 0011 0011 0011 0011 0011 01
#### 2.52
bias = 2^2-1=3
3-3=0
4*(1+1-1/16)=8 - 1/4
1/2*(1+1/2+1/16) = 1/2 * 25/16
1/2*(1+1/2) = 3/4
8*(2-1/16) = 16-1/2=15.5
1.1111 = 10.000
1/4*1
0001 0010
位 | 值 | 位 | 值 |
---|---|---|---|
011 0000 | 1 | 0011 000 | 1 |
101 1110 | 7.75 | 101 111 | 7.75 |
010 1001 | 0.78125 | 010 100 | 0.75 |
110 1111 | 15.5 | 111 000 | 16 |
000 0001 | 1/4 | 000? |
2.53
表达式 | 位 | 值 |
---|---|---|
x == (int)(double)x | True | |
x==(int)(float)x | INT_MAX | |
d==(double)(float)d | INT_MAX | |
f==(float)(double)f | True | |
f==-(-f) | True | |
1.0/2==1/2.0 | True | |
d*d >= 0.0 | True | |
(f+d)-f==d | 溢出 |
总结
- 对B,C,D,E的二进制不熟悉 就记住AC吧 1010 1100
- 4*k + b里面如果b=0 则为1 反之也如此
- xor: LEARNED: bis(bic(x,y),bic(y,x))
- !x的结果要不是0要不是1。
-(1<<m)
6.有限范围内的数的运算是模的运算,无符号数和补码在位级运算是一样的。 unsigned很容易出bug。
代码
#include <stdio.h>
typedef unsigned char* byte_pointer;
void show_bytes(byte_pointer start,int len) {
for (int i = 0;i < len;i ++) {
printf(" %.2x",start[i]);
}
puts("");
}
void show_int(int x) {
show_bytes((byte_pointer)&x,sizeof(int));
}
void show_float(float x) {
show_bytes((byte_pointer)&x,sizeof(float));
}
void show_pointer(void *x) {
show_bytes((byte_pointer)&x,sizeof(void *));
}
int main() {
show_int(16);
}