第二章——信息的表示和处理
三种重要的数字表示
- 无符号(unsigned)编码基于传统的二进制表示法, 表示大于或等于0的数字.
- 补码(two’s-complement)编码是表示有符号整数最常见的方式.
- 浮点数(floating—point)编码是表示实数的科学计数法的以2为基数的版本.
由于表示的精度有限, 浮点运算是不可结合的.
使用命令行指定C版本
linux> gcc -std=c11 main.c
信息存储
机器级程序将内存视为一个非常大的数组, 称为虚拟内存, 所有可能地址的集合就称为虚拟地址空间.
C语言中的一个指针的值都是某个存储块的第一个字节的地址.
16进制表示法
在C语言中, 以0x或0X开头的数字常量被认为是十六进制的值.
16进制和10进制转换
辗转相除法.
字数据大小
对于一个字长为w
位的机器而言, 虚拟地址的范围为0\sim 2^w -1
, 程序最多访问2^w
个字节.
long和char指针在字长为32位与64位的机器中的字节数分别为4和8.
C标准不保证char为有符号数(尽管大多数编译器将其视为有符号数).
寻址和字节顺序
两个规则: 对象的地址, 如何排列这些字节.
几乎在所有的机器上, 对象的地址为所使用字节最小的地址.
最低有效在最前面的方式称为小端法, 最高有效字节在最前面的方式称为大端法.
小端法显示数据顺序代码
#include <stdio.h>
typedef unsigned char* byte_pointer;
void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
}
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*));
}
void test_show_bytes(int val) {
int ival = val;
float fval = (float)val;
int* pval = &ival;
show_int(ival);
show_float(fval);
show_pointer(pval);
}
void main() {
const char* s = "abcdef";
test_show_bytes(12345);
printf("%.2x", 12345);
}
结果为
39 30 00 00 (内存中的表示形式)
00 e4 40 46
a0 f9 f7 00
3039(实际应该是这样的)
布尔代数的有趣性质
(a\hat{\space\space}b) \hat{\space\space} a=b
可以用来做无需第三变量的swap:
void inplace_swap(int *x, int *y){
*y = *x ^ *y;
*x = *x ^ *y;
*y = *x ^ *y;
}
移位运算
向右移位运算分为逻辑右移和算数右移, 逻辑右移用0补齐左空位, 算术右移用1补齐左空位(2次幂).
对无符号数, 必须为逻辑右移.