一. 再探位运算

1.1 左移 «

左移运算符将运算对象向左移动指定的位数,移出左末端位的值丢失,用 0 填充空出的空位

(111001)« 2

(100100)

1.2 右移 »

右移运算符将运算对象向右移动指定的位数,移出右末端位的值丢失。对于无符号类型,用 0 填充空出的位置;对于有符号类型,空出的位置用符号位填充

(111001)» 2

(111110)

左移一位,可看作乘以 2;右移一位,可看作除以 2

1.3 大端与小端

1.3.1 什么是大端,小端?

大端和小端是指数据在内存中的存储方式不一样

如 0x123456

大端模式

低地址 ——> 高地址
0x12 0x34 0x56

小端模式

低地址 ——> 高地址
0x56 0x34 0x12

1.3.2 为什么会有大端,小端?

一开始是因为不同架构的 CPU 处理多个字节数据的顺序不一样,比如 x86 的是小端模式,C51 是大端模式。

后来互联网流行,TCP/IP 协议又规定为大端模式,为了跨平台通信,还专门出了网络字节序和主机字节序之间的转换接口(ntohs、htons、ntohl、htonl)

1.3.3 怎样判断大小端

基本思想是根据数据的截断

通过强制类型转换截断

#include <stdio.h>

typedef enum{
    false,
    true,
}bool;


bool isBigEndian(void)
{
    short num = 0x1234;
    char ch = *(char*)&num;
    if(ch == 0x12)
        return true;
    else
        return false;
}

int main(void)
{
    bool res = isBigEndian();
    if(res == true)
        printf("BigEndian\n");
    else
        printf("SmallEndian\n"); 
    return 0;
}

利用联合体共享内存的特性,截取低地址部分

bool isBigEndian(void)
{
    union NUM{
        short num_1;
        char num_2;
    };
    union NUM num = {0x1234};
    if(num.num_2 == 0x12)
        return true;
    else
        return false;
}

二. GDB

gdb 是一个用来检查逻辑错误的调试工具,语法之类的错误是通过编译器来检查的

#include <stdio.h>
#include <string.h>

int main()
{
    int i;
    char a[1000];
    for(i = 0; i < 1000; i++)
        a[i] = -1-i;
    printf("%ld\n" , strlen(a));   //值是256,并不是1000;
    return 0;
}

1. 进入 gdb

gcc main.c -o run -g
gdb run

2. 退出 gdb

quit(q)

3. 列出源码

list(l)

list 命令一次只能显示 10 行,若想查看后面的源码,可一直按回车键(回车键会重复执行上一次执行的 gdb 命令),直到所有源码显示完

从头查看源码

list(l) 1

查看指定行数的源码

list(l) 5, 10 

查看指定函数周围的源码

list(l) main

4. 设置断点 可以在函数名、行号等上设置断点,程序运行后,到达断点就会自动暂停运行。此时可以查看该时刻的变量值,显示栈帧,重新设置断点或者重新运行等。

在指定行设置断点

break(b) line

在指定函数设置断点

break(b) function

查看当前断点信息

info(i) break(b)

5. 运行程序

run(r)

运行直到断点处

6. 查看变量的值

print(p) var

以二进制的形式打印

print(p)/t var

改变内存的内容

print(p) var=value

7. 继续执行断点后续指令

continue(c)

继续执行后续指令,直到遇到下一个断点

8. 下一条指令

会越过函数

next(n)

会进入函数

step(s)

9. 结束当前函数,回到函数调用点

finish

10. 查看变量的类型

ptype var

11. 查看函数参数值

info(i) args

12. 查看局部变量

info(i) locals

13. 查看内存的值

examine(x) /[n,f,u] address 

n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个单位的内存

f 表示显示格式,t 按二进制格式显示变量,d 按十进制格式显示变量,a 按 16 进制格式显示变量

u 表示单位长度,默认为 4 字节;b 表示单字节,h 表示双字节,w 表示四字节

// 显示一个字节,按二进制格式
x /1bt var

作业

编写一个函数来查找字符串数组中的最长公共前缀,如果不存在公共前缀,返回空字符串 “”

示例1:

输入: strs = [“flower”, “flow”, “flight”]

输出: “fl”

示例2:

输入: strs = [“dog”, “racecar”, “car”]

输出: ""

解释: 不存在公共前缀