第一部分(程序结构和执行)
信息存储
程序对象 = 程序数据 + 指令 + 控制信息
进制表示
二进制 -> 十进制 -> 十六进制
字数据大小
B->KB->MB->GB->TB->PB->EB
32位计算机 (字长4个字节)虚拟地址空间[0 , (2^32)-1]
64位计算机 (字长8个字节)虚拟地址空间[0 , (2^64)-1]
寻址和字节顺序
小端法:最低有效位在最前面
大端法:最高有效位在最前面
typedef 命名数据类型
指针&数组
指针的创建和间接引用(取地址运算符&创建一个指针,&x创建一个指向保存变量x的空间地址的指针)
表示字符串
Unicode
UTF-8
#include <stdio.h>
#include <string.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 *));
}
int main(int argc, char const *argv[])
{
// int ival;
// printf("please input an integer:\n");
// scanf("%d",&ival);
// //printf("%d\n",ival);
// float fval = (float)ival;
// int *pval = &ival;
// printf("%p,%p\n", pval,&ival);
// show_int(ival);
// show_float(fval);
// show_pointer(pval);
// int val = 0x87654321;
// byte_pointer valp;
// valp = (byte_pointer) &val;
// show_bytes(valp,1);
// show_bytes(valp,2);
// show_bytes(valp,3);
char *str = "abcdef";
byte_pointer str_val = (byte_pointer) str;
show_bytes(str_val,strlen(str));
return 0;
}
表示代码
布尔代数简介
位级运算
~ //not
& //and
| //or
^ //exclusive-or 异或
布尔环
创建掩码
bis;
bic;
bis(x,y);//x|y
bis(bic(x,y),bic(y,x));//x^y
异或操作就是把x,y相同的位变为0,然后再进行或操作
C语言中的逻辑运算
||;//or
&&;//and
!;//not
逻辑运算认为所有的非零的参数都表示位TRUE
换言之,用逻辑运算符进行的逻辑运算的结果只有0或者1
只使用位级运算和逻辑运算,写一个C表达式,它等价于x==y
!(x^y);
C语言中的移位运算
逻辑右移
算术右移
加减法的优先级高于移位运算
整数表示
整型数据类型
32位计算机和64位计算机关于long的取值范围不同
无符号数的编码
无符号数的编码具有唯一性
补码编码
补码编码具有唯一性
PS:-1的补码的8位表示为0xFF, 16位表示为0xFFFF
|Tmin| = |Tmax| + 1
Umax = 2Tmax + 1
反码和原码
反码最高位的权是
-(2^(w-1)-1)
原码最高位是用来表示符号的
几乎所有的计算机都使用补码编码
有符号数和无符号数之间的转换
数值可能会改变,但是位模式不变
同一个位模式的两个数值(补码和无符号数)的和为2的w次方(w是位数)
C语言中的有符号数与无符号数
%d //有符号十进制
%u //无符号十进制
%x //十六进制
扩展一个数字的位表示
零扩展
符号扩展
截断数字
截断无符号数
截断补码数值
关于有符号数和无符号数的建议
无符号数的 0-1 会变成模数加法
size_t //unsigned int
尽量不去使用无符号数
整数运算
无符号加法
算术运算溢出
判定溢出
阿贝尔群
无符号数求反
加法逆元
补码加法
负溢出
正常
正溢出
判定溢出
/* Determine whether arguments can be added without overflow */
int tadd_ok(int x, int y)
{
int sum = x+y;
int neg_over = x<0 && y<0 && sum>=0;
int pos_over = x>0 && y>0 && sum<0;
return !neg_over && !pos_over;
}
补码相反数
if (y == Tmin) //-y==Tmin
{
if(x<0)
{
x-y;//不会溢出
}
else
{
x-y;//会溢出
}
}
补码的非
补码的非的位级表示技巧
-x = ~x+1;
x = [1100];//4
-x = [0100];//-4
x=[1000];//-8
-x=[1000];//-8
x=[0101];//5
-x=[1011];//-5
无符号乘法
补码乘法
/* Determine whether arguments can be multiplied without overflow */
int tmult_ok(int x, int y)
{
int p = x*y;
/* Either x is zero, or dividing p by x gives y */
return !x || p/x==y;
}
/* Determine whether arguments can be multiplied without overflow */
int tmult_ok_v2(int x, int y)
{
int64_t p = (int64_t)x*y;
return p == (int)p;
}
乘以常数
(x<<3)+(x<<2)+(x<<1); //x14
(x<<4)-(x<<1); //x14
除以2的幂
关于整数运算最后的思考
浮点数
二进制小数
IEEE浮点表示
规格化的值
非规格化的值
特殊值
舍入
向偶数舍入时,在50%的时间里,采用向上舍入,在另外50%的时间里采用向下舍入
二进制小数舍入
浮点运算
浮点加法不具有结合性