CSAPP Lecture 02 - Bits ,Bytes and Integers

Lecture 02 - Bits ,Bytes and Integers

视频地址:https://www.bilibili.com/video/BV1iW411d7hd?p=2
课程地址:https://www.jianguoyun.com/p/DecAyVEQjqmrChiahrEE
思维导图:https://www.jianguoyun.com/p/DclOTz8QjqmrChi_hrEE

1. Bit

信息为什么用位来表示?

  • 易于存储和传输

  • 易于转化成其他进制

bit级别的操控

  • 布尔代数(& | ^ ~)

  • 逻辑运算(&& || !)

  • shift(<< >>)

2. Integers

有符号数和无符号数的表示

  • 无符号数:

    • 公式:\(B 2 U(X)=\sum_{i=0}^{w-1} x_{i} \cdot 2^{i}\)
    • 取值范围(000...0,111...1)
  • 有符号数:

    • 公式:\(B 2 T(X)=-x_{w-1} \cdot 2^{w-1}+\sum_{i=0}^{w-2} x_{i} \cdot 2^{i}\)

    • 取值范围(100...0,011...1)

    • 最大值比最小值的绝对值少1

    • 4bit无符号数与有符号数的位表示:

    -

无符号数与有符号数之间的转换

  • 根本原则:维持符号位不变,但重新释义
  • 实际效果:正数部分不变,负数加减2^w

整数运算

  • 加法:

    • 无符号数:超限部分会被截短

      • \(s=\operatorname{UAdd}_{w}(u, v)=u+v \bmod 2^{w}\)
      • image-20220307165858893
    • 有符号数:超限部分会被重新释义

      • image-20220307165921533
  • 乘法

    • 无符号数

      \(\text { UMult }_{w}(u, v)=u \cdot v \bmod 2^{w}\)

    • 有符号数:除了符号位以外,和无符号数一样,

  • 使用unsigned的合适时机

    • 循环里面最好不要使用

      • unsigned 可能出的问题:0-1=Umax
        用在循环里面的时候要特别注意

        • 错误的写法:
        image-20220307170150314
        • 正确的写法:

    • 在进行取模运算,shift运算的时候可以使用

3. 数据在内存中的存储形式

大端模式与小端模式

  • 大端:最低字节具有高地址

    • 代表机器:Sun,PPC MAC,Internet
    • image-20220307170316114
  • 小端:最低有效字节有低地址

    • 代表机器:x86,ARM,IOS, Windows

    • image-20220307170338321

程序:打印数据在内存中的存储形式

#include <iostream>
using namespace std;

typedef unsigned char *pointer;

void show_bytes(pointer start,size_t len){
    size_t i;
    for(i=0;i<len;i++){
        printf("%p0x  %.2x\n",start+i,start[i]); //%p表示按照16进制输出数据,数据不够则在左边补0
        printf("\n");
    }
}

int main(){
    int a= 15213;
    show_bytes((pointer)&a,sizeof(a));
    system("pause");
    return 0;
}

运行结果:

000000000061fe1c0x  6d

000000000061fe1d0x  3b

000000000061fe1e0x  00

000000000061fe1f0x  00

代码安全性

示例1:copy_from_kernel

在linux中有一个从内核拷贝数据到用户态的代码,源代码为:

/* Kernel memory region holding user-accessible data */
#define KSIZE 1024
char kbuf[KSIZE];

/* Copy at most maxlen bytes from kernel region to user buffer */
int copy_from_kernel(void *user_dest, int maxlen)
{
    /* Byte count len is minimum of buffer size and maxlen */
    int len = KSIZE < maxlen ? KSIZE : maxlen;  //为什么要加长度判断?
    memcpy(user_dest, kbuf, len);
    return len;
}

代码段中第9行为什么要加长度判断呢?

为了阻值恶意的使用!比如:

#define MSIZE 528
void getstuff() {
	char mybuf[MSIZE];
	copy_from_kernel(mybuf, -MSIZE);
}

通过长度判断,可以阻止用户访问无权限的代码段。

示例2:copy_from_kernel

这个函数的目的是将ele_src中的连续内容,分成ele_cnt块,每块ele_size大小,放入新malloc的地址内

void *copy_from_kernel(void *ele_src[], int ele_cnt, size_t ele_size)
{
    /*
* Allocate buffer for ele_cnt objects, each of ele_size bytes
* and copy from locations designated by ele_src
*/
    void *result = malloc(ele_cnt * ele_size);  //分配一块  ele_cnt*ele_size大小的空间,返回初始地址指针
    if (result == NULL)
        /* malloc failed */
        return NULL;
    void *next = result;
    int i;
    for (i = 0; i < ele_cnt; i++)
    {
        /* Copy object i to destination */
        memcpy(next, ele_src[i], ele_size);
        /* Move pointer to next memory region */
        next += ele_size;
    }
    return result;
}

乍看上去没有问题,但是如果取

ele_cnt = 2^20+1

ele_size = 4096 呢?

解答:

malloc的原型是:

void *malloc(int size);

那么malloc将分配一块2^32+4096的地址,超过了int的适用范围 2^32,会分配失败!

如何保证分配正确?

ele_cnt * ele_size的大小进行判断和限制!

整数的特性

  1. 整数加法的“环性”:包括交换律、结合律、加减可逆性
  2. 整数满足 ~x + 1 = -x 因为 ~x + x = 11111...1 = - 1

编译器对于除法的实现

C语言在进行除法运算时,对计算结果是会进行四舍五入的

image-20220308155441193

对于2^k的除法,一般采用右移进行快速实现,但怎么进行小数部分的四舍五入呢

编译器进行了优化,实际上使用的是是(x+2^k-1)/ 2^k

image-20220308155356175
posted @ 2022-03-08 16:35  逍遥一叹s  阅读(95)  评论(0)    收藏  举报