GDB学习笔记
关于GDB调试工具的学习笔记,学会了纯命令行的调试操作,才能更好地理解例如VSCode提供的图形界面的调试功能等,GDB在WSL2
Ubuntu上进行操作。
调试信息
可执行程序可以被调试的前提就是编译时加上了调试信息,通常是debug模式下,加上-g选项。
如果强行调试一个没有调试信息的可执行程序,将不能看见程序中的函数名或变量名等,而只是内存地址,并且会显示一条警告
1(No debugging symbols found in <program>)
加载程序
正常情况下可以通过调试器来加载程序 1gdb <program>
也可以先启动gdb,然后加载可执行文件 12gdb(gdb) file <program>
加载的程序并不会直接执行,需要使用start或run命令来启动程序。
如果是需要调试一个生成core文件并异常终止的程序,可以加上core文件来恢复现场
1gdb <program> <core dump file>
如果需要调试一个正在运行的程序,可以加上进程ID(一个整数),gdb将会自动以attach模式 ...
Git学习笔记——4. 底层原理
仓库配置信息
.git/logs/和.git/info/,顾名思义是一些日志和辅助信息。
.git/hooks/ 存储一些 Git
提供的钩子脚本的模板,例如(pre-push.sample),可以创建名为pre-push的钩子脚本,这个脚本在特定行为(push
之前)会自动执行,其他名称的钩子也是类似的。
.git/config 是仓库级的 Git
配置文件,优先级最高,但是配置只是局限在当前仓库中,可能包括如下内容:
123456789101112[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true ignorecase = true[remote "origin"] url = git@github.com:xxx.git fetch = +refs/heads/*:refs/remotes/origin/*[branch "main"] remote = origin merge = refs/heads/main
...
Git学习笔记——3. 远程仓库
远程仓库基础
本地仓库可以和服务器上的远程仓库建立联系,通常将架设在服务器上的仓库用于备份或者开源,有如下特点:
本地和远程仓库的网络通信通常基于ssh或https协议,两者的区别在于权限,例如是否需要每一次推送操作输入密码确认等
可以有多个远程仓库,虽然个人使用时通常只需要一个
origin
是习惯上默认的远程仓库名称,当然也可以改成其他名称,有些命令在缺省时会尝试对名为origin的远程仓库进行操作
远程仓库和本地仓库在地位上是不等价的
单纯的添加操作对远程仓库没有任何影响
拉取和推送都只能由本地仓库向远程仓库发起,远程仓库并不能主动向本地仓库发送信息
本地仓库向远程仓库发起推送或拉取可能会受到权限限制,尤其是在多人合作的项目中
由于本地仓库和远程仓库都存在HEAD和分支,在逻辑管理上更加复杂,从实现的角度来说:
本地的HEAD和分支是可修改的,具体实现在.git/refs/heads中
远程仓库的HEAD和分支是只读的,只是一个影子或书签。对于每一个远程仓库,HEAD和分支的具体实现在.git/refs/remotes/<remote_name>/中,例如对 ...
Git学习笔记——2. 撤销操作
现在关注Git的常见撤销操作。 撤销操作在某些情形下是危险的,这指的不是
Git 数据库中的内容丢失(这几乎很难办到),而是最新的修改可能丢失:
如果修改被正式提交了,那么即使回滚了版本,也可以通过哈希值或历史记录来恢复
如果使用git add添加到
index,那么即使撤回了,也可以通过哈希值或历史记录来恢复
如果最新的修改没有添加到 index,那么这些本地修改确实有可能直接被 Git
的某个切换操作或撤销操作覆盖,导致修改的丢失
Git 撤销原理
reset
git reset 是一个非常重要的重置操作,原型如下
1234git reset [-q] [<tree-ish>] [--] <pathspec>…git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>…]git reset [--s ...
Git学习笔记——1. 基础
关于 Git
的学习笔记整理,这部分资料准备了很久,因为中文的教程大都过于简略,并且不涉及原理,学不明白,至于英文的文档也过于复杂,各种参数选项非常复杂。学习笔记的内容并不是由浅入深地介绍Git,而是一个梳理笔记,主要参考Git 官方手册
Git 必要配置
Git 的配置分成三层:
第一层是仓库级,在仓库目录下,文件为.git/config
第二层是用户级,在用户主目录下,文件为~/.gitconfig(主要修改的是用户级配置)
第三层是系统级,在安装目录下,安装时的选项会保存在这里
范围越小的配置文件优先级越高。除了这几个配置文件,还有一些可选的辅助配置文件,例如
关于排除文件的规则配置 .gitignore
关于文件格式的配置 .gitattributes
值得注意的,Git在每次操作时,会检查当前工作目录中实际存储的.gitignore以及其它配置文件,而不是Git保存的最新版本,即使我们修改了.gitignore,也不需要先单独提交.gitignore,它的规则会立即生效。
我们主要关注用户级配置文件,有如下常用的设置:
添加用户名和邮箱,这是用于在提交信息上署 ...
Python学习笔记——11.类型注解
虽然 Python
作为动态语言具有极高的灵活性,编程非常便利,但是为了让程序更加清晰可读,有必要加入类型注解,要求
Python 3.9+,一些关于类型注解需要的内容在 typing
模块,下面有的语句在高版本中可以省略导入typing模块。
类型注解不是强制的,并不会真正影响Python脚本的执行,但是静态代码检查可以基于类型注解提供警告,以提高编程的可靠性。这种类型检查的使用也很繁琐,容易误报警告,过度使用类型注解会丧失Python的灵活性。
变量注解
在定义变量时可以注解它的类型,这对静态代码分析很有帮助,例如
12age: int = 20age = '20'
第二行会标红:静态检查不通过,但是代码仍然可以正常执行。
注意:
在 VScode+jupyter 中,只有处于同一个 cell
的代码才会执行静态检查,不同 cell 之间不会进行检查。
这种变量类型注解写错了可能找不出来,例如
age: float = 20,这不会影响程序执行效果,但是会误导静态分析。
例如几种基本的类型
1234a: int = 3b: float = 3.14c: ...
Python学习笔记——10.基本类型常用操作
记录一下涉及到字符串,列表,元组和字典这几个基本类型的常用操作吧。
字符串
字符串的本质是就是一些字符组成的不可变序列,Python把单个字符视作长度为1的字符串进行统一处理。使用字符串字面量来定义一个字符串对象
1s = 'abcd'
索引
可以使用索引获取指定位置的字符:
正向索引从第一个字符开始,依次为s[0],s[1]...
反向索引从最后一个字符开始,依次为s[-1],s[-2]...
1234s = "abcd"s[1] # "b"s[-1] # "d"
超出实际范围的索引会报错。
字符串是不可变的,因此通过索引获得的只是可读的,不能进行修改
123s = "abcd"s[0]='a' # 报错
切片
可以使用切片获取字符串片段来创建新的字符串,切片的基础语法为str[lower:upper:step],lower代表切片的起点,upper代表终点(不含),step代表步长(省略时默认为1)
切片的具体语法非常灵活,这里只给出几个例子 12345678 ...
Python学习笔记——9.变量
变量作为Python中最基础的概念,但是我却很难捋清楚它的概念,因此放在了笔记的后面。
Python的变量使用非常灵活方便,但是这也导致了Python变量的底层原理不易理解,这一点与C/C++的变量完全不同。
在这篇笔记中,重点区分几个概念:
字面量:字面值是内置数据类型常量值的表示法
对象:对象具有类型,类型实例化得到对象
变量:可以指向一个任何类型对象的指针
关于字面量和字面量集的表示语法在前面已经介绍过,这里不再重复。
对象
在 Python 中,一切皆为对象,函数也是对象。
每一个对象都具有类型,对象是类型的实例,这些是面向对象的通用概念,在Python中也一样成立。
我们不需要像 C++一样手动管理内存中对象的创建与销毁,而是由 Python
虚拟机的负责(本质还是通过 C 的 malloc 之类的函数),内存回收机制 GC
负责管理和自动销毁没有被变量直接指向或间接使用的对象。GC的判定方法可以理解为对每一个对象都维持一个引用计数,如果计数为零则删除,和
C++的智能指针类似。事实上,我们无法在Python中显式地销毁内存中的任何对象。
基本数据类型可以分成两类:
不 ...
Python学习笔记——8.函数与类进阶
现在关注几个函数和类的进阶概念:迭代器,生成器,闭包,装饰器等。
迭代器
Python 内置的列表等可以支持 for
遍历,本质上是因为列表等提供了迭代所需要的接口,我们可以让自定义类也支持迭代遍历。
首先,for 遍历的实质,以下面的例子说明 123456789s = 'abcd'it = iter(s)print(next(it)) # aprint(next(it)) # bprint(next(it)) # cprint(next(it)) # dprint(next(it)) # 迭代终止,抛出StopIteration异常
对于一个自定义容器类
Demo,我们希望它支持迭代器遍历,那么需要实现如下的内容:
容器类(或者说可迭代对象)提供 Demo.__iter__
方法,返回一个迭代器类 Iter,迭代器需要记录当前状态
迭代器类提供 Iter.__next__
方法,返回容器中的元素,并且在迭代完成后抛出 StopIteration
异常,这个异常会被 for 语句自动捕获。
例如一个反向迭代器 12345678910111213141516171 ...
Python学习笔记——7.输入输出
现在关注Python的输入输出,这里并不会对各种输入输出语法进行详细的介绍,只是针对几种可能的需求,够用就行。
print 基本输出
函数原型
1234567def print( *values: object, sep: str | None = " ", end: str | None = "\n", file: SupportsWrite[str] | None = None, flush: Literal[False] = False,) -> None: ...
例子
12345print("hello,world!")# hello,world!a = 1; b = 2; print("a=",a,"b=",b)# a= 1 b= 2
这里如果连续打印多个项,会默认加上空格分隔,可以用关键字参数更改sep。
12print("hi","Alex",sep='-')# hi-Alex ...