程序员的自我修养 - 读书笔记文字版

第1部分 简介

第1章 温故而知新

  1. 程序在运行的时候先通过分段(segmentation)的方式将虚拟地址空间与真实的物理内存地址空间进行一一的映射,但是这种方式每次换入换出的是整个程序,导致IO变大,更具局部性原理,可以采用分页(Paging)来解决. 分页就是将地址空间人为的等分成固定大小的页,每页的大小(4KB或者4MB)由操作系统确定。 几乎所有操作系统都采用4KB的分页,那么对于一个32位的程序来说,最多只能有4GB/4KB = 1048576页, 物理空间也是同样的分法。但是当真实物理空间不够虚拟空间的页数的时候,真正有效的空间以真实内存空间为准。页的映射是由MMU部件来完成的。MMU一般集成在CPU内部。

  2. 外设使用总线地址,CPU使用物理地址。x86平台上,物理地址和总线地址相同。

  3. 线程可以分为IO密集型线程和CPU密集型线程,当CPU密集型线程的优先级较高的时候,可能会导致低优先级的线程被饿死,而IO密集型线程获得较高优先级的时候,由于大部分时间是处于等待状态,所以不叫不容易造成其他线程的饿死。 如果一个线程长时间得不到执行,调度系统会逐步提升它的优先级让它执行。

  4. 线程还可以分为抢占线程和不抢占线程,抢占线程是那些时间片用完之后会被剥夺执行权的线程,不可抢占线程是那些除非执行完毕否则不能剥夺执行权的线程。时至今日,非抢占线程已经十分罕见。

  5. windows对于进程和线程的实现如同教科书一般的标准,但是在linux中其实并没有严格的线程和进程的概念,Linux中所有的执行实体都被成为任务Task,每一个任务概念上类似于一个单线程的进程,但是它的不同任务之间可以选择共享内存空间,因此在实际意义上共享了同一内存空间的多个任务构成了一个进程。

  6. 为了保证多线程环境下操作的原子性,有以下几种办法:
    6.1 锁
    6.2 二元信号量和多元信号量
    6.3 互斥量,和上面两个的区别是哪个线程建立的互斥量就必须由哪个线程去释放
    6.4 临界区,和上面几种的区别是,哪个进程创建临界区的锁,就由哪个进程获取,对其他进程不可见。
    6.5 读写锁,有两种获取方式独占式和共享式,区别如下

读写锁状态以共享方式获取以独占方式获取
自由成功成功
共享成功等待
独占等待等待
6.6 条件变量 ,相当于一个栅栏
  1. 可重入线程是并发安全的强力保障,一个可重入的函数可以在多线程环境下放心使用。

  2. 三种线程模型
    8.1 一对一模型
    8.2 多对一模型
    8.3 多对多模型


第2部分 - 静态链接

第2章 编译和链接

  1. 程序编译运行的流程是 预编译-编译-汇编-链接, 命令分别是:
    gcc -E xx.c -o xx.i
    gcc -S xx.i -o xx.s 或者(cc1 xx.i)
    gcc -c xx.s -o xx.o 或者(as xx.s -s xx.o)
    以及 ld xxx.o xxxx.o xxxx.o等

  2. 目标文件即.obj文件或者.o文件,本质上是函数的集合,用于重定位, 他们的内部函数和变量的存储方式和真正的可执行文件一样只是在结构上稍有不同。

第3章 目标文件里有什么

  1. PC流行的PE文件格式和ELF文件格式都是COEF格式的变种。

  2. bss段只是为全局变量和局部静态变量预留位置,在elf文件中不占空间。

  3. x86的cpu中字节序采用小端模式存储(所以elf文件中变量的存储采用小端), arm架构的cpu中采用大端,网络字节序(TCP/IP)采用大端传输。

  4. elf文件主要包含,代码段(.text)和数据段(.data, .rodata, .bss), 未初始化的全局变量和和未初始化的局部静态变量被存放在.bss段(有时候未初始化的全局变量也会存放在符号表中)。 字符串一般在.rodata段,也有的在.data段。值得一提的是赋值为0的局部静态变量也会被认为是未赋值从而放置在bss 段而不是data段。 attribute 命令可以在代码中指定变量或者函数存放在elf文件的那一段

  5. reaelf -h xx.o可以输出elf文件的文件头信息。 ELF文件最开始的16个字节代表了ELF文件的平台属性,其中前四个字节是ELF文件的魔数,不同平台的魔术不同(ELF的魔数是0x7f, 0x45, 0x4c, 0x46 即 DEL控制符,‘E’,‘L’,‘F’ PE/COEF的魔数是0x01, 0x07, 即’M’,‘Z’), 操作系统在加载可执行文件的时候会确认魔数是否正确,如果不正确会拒绝加载。
    第5个字节是用来标识文件类型,0x01是32位的,0x02是64位的。第6个字节表示字节序是大段或者小端,第七个字节表示ELF的主版本,一般是1。后面9个字节没有指定,表示可扩展。

  6. ELF文件中段表的位置由e_shoff成员决定,即(Start of section headers的值决定段表的起始位置)。 readelf -S xx.o 可以显示真正的段表结构。

  7. elf文件中段表是其中的一个段,段表里面存储了其他各个段的起始地址和大小还有其他一些信息。

  8. 符号表里面存储了全局变量,全局函数和行号和用于调式和核心转储的局部符号,行号等信息,链接器在链接的时候只关注全局函数和变量。 可重定位文件中包含的局部信息对其他重定位文件来说都是不可见的,只有全局函数和变可见。可以用nm来查看elf文件的符号结果。 符号表也是elf文件中的一个段,段名一般叫做.symtab

  9. readelf -s xx.o可以打印输出elf包含的符号表的信息。 分别有符号的类型,值(函数或者变量的地址),大小,绑定信息(局部,全局,弱引用), Ndx表示符号所在的段的下标,该下标可以通过readelf -a xx.o 看到。 值得注意的是符号表中第一个符号,即下标为0的符号永远是一个未定义的符号。
    对于STT_SECTION类型的符号,它们的符号名没有显示,其Ndx所对应的段名也就是这里的符号名, 因为他们是段名符号。可以通过 objdump -t 看到这种段名符号

  10. 特殊符号是由ld链接器定义的,程序中只需要申明就可以使用,程序在最终链接的时候会自动转化为正确的值,例如__executeable_start, __etext或_etext或etext, _edata或者edata, _end或者end等等。

  11. 为了防止函数和全局变量在各文件之间的命名冲突。但是随着操作系统和编译器的分化,GCC已经不用在符号前面加_但是windows平台下的编译器还保持着前面加_这样的传统。此外GCC在windows平台下下编译器例如cywin和mingw还保持着这样的传统。GCC本身可以通过编译器选项-fleading-underscore或者-fno-leading-underscore来打开或关闭是否在C语言符号前加下划线。

  12. 函数签名是C++引入的区别不同类,命名空间等不同作用域名中相同名称的成员的机制 binutils提供的 c++filt命令可以解析一个函数修饰后名称对应的真正的函数签名。一般规则是对于在命名空间或者类的中的变量和函数其前面一般是_ZN开头,以E(+)i/f/d结尾。最后值得说明的是不同平台的编译器的对同一函数的函数签名可能是不同的。 VC++的函数签名方法没用向外公开,但是其UndecorateSymbolName()的api可以将修饰后的名称转换成函数签名。
    由于不同编译器采用不同的名字修饰方法,所以导致了不同编译器产生的目标文件无法正常的相互链接,这也是导致不同编译器之间不能互操作的主要原因之一。
    目标文件即OBJ文件是跨平台的

  13. extern "C"{}语句会导致受作用的变量和函数名在修饰之后采用的是C语言的格式而不是C++. 对于同一个变量或者函数,C++和C语言的修饰不一样,为了让C++能正确引用并使用C语言的符号,通常在声明这个函数的时候会先判断当前的编译单元是C还是C++即使用下面的语句

#ifdef __cplusplus
extern "C"{
#endif

void *memset {void *, int , size_t};

#ifdef __cplusplus
}
#endif

这种技巧几乎出现在任何系统头文件中(源文件已经判断了C或者cpp所以不需要这样写)

  1. 强符号和弱符号,一般初始化了的全局变量和函数未强符号而未初始化的全局变量为弱符号,强若符号有以下规则
14.1 不允许强符号重复定义
14.2 如果一个符号在某个目标文件中是强符号,其他目标文件中是弱符号,则选择强符号
14.3 如果一个符号在多个目标文件中都是若符号,则选择占用空间最大的那个。

弱符号和链接器的COMMON块概念的联系很紧密

15 强引用和弱引用: 如果引用的一个库中的符号没用被定义,则链接时候会报为定义错误,这是强引用, 这种情况不报错的就属于弱引用。 弱引用和弱符号对库十分有用,因为这样用户可以自定义库中函数,也可以在去掉了某些模块之后程序依然可以正常链接,着使得程序更容易裁剪和组合。

16 使用gcc/g++ -g参数可以在目标文件中保存调试信息,ELF文件的标准调试信息格式是DWARF, 目前是 DWARF 3, 微软的调试信息标准格式叫CodeView. 调试信息通常数倍于ELF文件本身的内容, 发布时候必须去掉。 在Linux下,可以使用strip去掉ELF文件中的调试信息


第4章 静态链接

  1. 空间地址分配有按序叠加和相似段合并两种方法,一般都使用相似段合并的方法。最后的可执行文件当中包含了可重定位的.o文件里面的所有指令。

  2. Linux下,ELF可执行文件默认地址从0x08048000开始分配。生成的可执行elf文件中的.text段是各个.o文件的.text段大小之和

  3. elf文件中需要重定位的段都有一个相对于重定位段(表), 利用objdump -r xx.o 可以查看目标文件的重定位表。

  4. 对于弱符号,即未初始化的全局变量,由于在编译成目标文件之后,编译器不能确定其大小,所以将其放在COMMON块中,但是当链接器分析完各个目标文件之后就可以确定其大小,从而将其放在BSS段,所以总体来看,未初始化的全局变量还是放在BSS段的。可以在GCC编译的时候使用fno-common指定未赋值的全局变量不在COMMON块中, 也可可以在代码中写__attribbute__ ((nocommon))将其当成强符号处理。

  5. 重复代码消除,例如C++的模板技术使得模板可以在多个源文件中别实例化但是编译器并不能知道它在多处被同一种数据类型实例化,所以现在主流编译器例如GNU 的做法是在每一个目标文件中对于一个模板的同一种实例化使用一种相同的名称,这样在链接阶段,链接器会检查这些重复的段并只保留一份。GCC把这种段叫"Link Once"命名为".gnu.linkonce.name" . VC++叫做COMDAT
    这种做法的一个潜在的问题是,当编译器对不同的编译单元使用不同的编译优化选项的时候,可能会使得相同名称的段有不同的内容,编译器的做法是随意选择一个作为链接的输入且提供警告信息。

  6. 函数级别链接: 通常的链接过程都是文件或者编译单元级别的链接,但是当只需要使用某个目标为见中的一个函数或变量的时候,就需要全部包含该文件,导致体积很大,编译器为此专门提供了函数级别的链接,与重复代码消除和相似,编译器将所有函数都想模板函数一样单独保存到一个段中,需要的时候再将其包含到输出文件,其他的则直接抛弃,这虽然较小的最终文件的体积但是由于段的数目增减,减慢了编译和链接的过程。GCC使用-fdata-sections-ffunction-sections可以将变量或者函数分别保存到独立的段中。

  7. 全局构造与析构: 全局对象的构造在main函数之前执行,全局对象的析构在main函数之后哦执行,Linux下的入口函数是_start,用于在main执行前进行初始化。为此,ELF文件提供了两个特殊的段.init.fini。其中.init中保存的指令是main执行之前Glibc的初始化部分, .fini中是main函数正常退出之后Glibc会安排执行的代码。

  8. 为了使得不同平台的目标文件兼容,即可以相互链接,这些文件必须有一直的ABI(Application Binary Interface),即二进制兼容,ABI内容包括符号修饰标准,变量内存布局,函数调用方式等等。厂商不希望用户看见自己的源代码所以会提供二进制版本,所以二进制兼容在大型项目中变得很重要。目前编译器的两大阵营 VISUAL C++和GNU 的GCC各执己见互不兼容。ABI兼容问题还有待解决

  9. 一个静态库文件(.a)是由许多.o文件合并而来的,linux下使用ar -t xx.a可以查看.a文件中包含的.o文件。在windows平台下可以使用lib /LIST xx.lib查看

  10. 可以使用objdump -t xx.a | grep xxx查找特定的目标文件。使用gcc -static --verbose -fno-builtin hello.c可以将编译链接过程的中间步骤打印出来, 即使我们写的代码非常简单,这也是一个非常长的依赖关系。这个过程会链接部分会显示collect2这是ld的一个包装,会调用ld

  11. BFD(Binary File Descriptor library)是基于所有硬件平台(不同的处理器和目标文件格式)的一个抽象层,基于BFD可以不用关心具体的硬件格式,而进行统一操作,因为BFD中已经包含了这些CPU和可执行文件的格式信息,ubuntu下BFD软件包的名字叫binutils-dev.

第5章

  1. windows上的目标文件为COEF格式,而可执行文件是PE格式,PE又是COEF格式衍生出来的, 所以将这类文件统称为PE/COEF格式

  2. 64位的Windows中对PE文件格式做了一点小小的修改,叫做PE32+格式,只是将32位的字段换成了64位而已。

  3. VC++有一些对C/C++的专用拓展,使用cl编译的时候,可以使用 /Za来禁用这些拓展,也可以在程序中使用宏__STDC__来查看VC++是否禁用了这些语法拓展

  4. 和GNU对象,Windows上的cl就是gcc, link就是ld, dumpbin就是objdump,

  5. PE中有两个ELF文件中不存在的段,分别是.drectve.debug$S. .drectve段是编译器传递给链接器的指令,其中的flags表示了他的特点。 .debug$S表示的是符号相关的调试信息。其中有原始文件信息和编译器信息

  6. 可以在cl命令中通过/ZI来关掉默认C库的链接指令

  7. PE文件为了兼容DOS的MZ文件结构在PE文件中加入了DOS的相关设置,所以将windows下的可执行文件在DOS上运行的时候会输出"This program cannot be run in DOS"

第3部分 装在与动态链接

第 6章

  1. 程序和进程的区别,程序就是菜谱,是一个静态概念, 进程就是菜,是一个动态概念。

  2. 程序的寻址空间由CPU的位数决定,所以32位下的程序寻址空间是 2 32 b i t 2^{32} bit 232bit即4GB, 64位下是17179869184 GB, 32位下C语言指针的长度是4字节,64位系统下长度是8字节.

对于一个32位的程序,寻址空间虽然是4GB,但是程序并不能全部使用,例如在Linux下,1GB是留给操作系统的,剩下的3GB给进程,且这3GB内存程序也不能完全使用,还有一部分给其他用途; 在Windows上,默认情况下2GB留给系统,2GB留给进程, 但是可以通过修改winows根目录下Boot.ini文件调整内存分配和linux下一样。
1995年Pentium Pro CPU使用PAE(Physical Address Extension),将地址线扩充到了36位,所以理论上计算机可以寻址的空间变成了64G, 但是进程的寻址空间仍然是4G(32位系统下指针是4个字节)

为了使应用程序能使用超过32位的内存,Windows上可以使用AWE(Address Window Extension)的方式, 在Linux上可以使用mmap(),但是这只是一种补救32地址线的方法, 在原来16位的DOS上也曾有过这样的做法。

  1. 为了提高内存的使用效率,采用动态装入的办法,动态装入由两种方式,第一种是覆盖装入,即每次将要使用的模块装入内存,不使用的调出,这样,调用的程序可以共享同一块内存区域,使用之前先要将程序的所有调用关系组织成一个树状结构。但是这种方式需要保证两点, 1) 调用路径上的模块都应该存在,2)不能存在跨树调用。 第二种是叶映射的方式,即将内存和文件存在的磁盘空间都划分成一个一个的页(通常是4KB),在程序使用的时候将相应的页调入,决定页面替换的算法由先进先出(FIFO)和最近最长使用算法等。
    由于每次将同一页程序装入内存中时的地址可能并不一样,所以加入按实际物理地址进行操作,那每次都需要重新读取地址,所以MMU就用来在实际物理地址和虚拟地址之间转换,
  2. 进程的建立过程:
    4.1 创建虚拟地址空间,也就是分配一个页目录。
    4.2 读取可执行文件头,建立虚拟地址空间和可执行文件的对应关系(可执行文件被装载时其实就是被映射的虚拟空间,所以也被称为映像文件)
    4.3 将CPU指令寄存器设置成可执行文件的入口(也就是可执行文件代码段的其实地址)
  3. ELF文件的链接视图和执行视图,链接视图是按照Section分配,执行试图又是Segment,Segment是将相同属性(只读,可读写,可读可执行)的Section作为一个Segment. 一般在链接的时候说"段"指的就是Section,在装载的时候说"段"指的是Segment
    readelf -S xx可以输出可执行文件中的section,而readelf -l xx可以输出可执行文件中的Segment(即程序头表),即怎样被装入进程空间, Segment中只有类型是LOAD的部分会被映射,这部分在装载之后又会被映射到两段VMA,分别是可读可写的部分和可读可执行的部分,
  4. ELF可执行文件和动态链接文件都有一个结构叫程序头表,保存着程序被装载时候的Segment信息,而静态目标文件没有这个程序头表,因为目标文件不需要被装载。
  5. 操作系统会通过给进程空间划分出一个个的VMA来管理进程的虚拟空间,基本原则是将相同权限属性,有相同映像文件的映射成一个VMA,一般包含四个区域:代码VMA,数据VMA,堆VMA,栈VMA,栈通常也叫堆栈。
  6. 程序员可以操作的进程空间,理论上linux下是3GB,windows下是2GB,但是操作系统为了防止恶意攻击,使用了一种叫做随机地址空间分布的技术,使得真正的堆区可用空间比理论上要少。
  7. 在Linux系统中,为了使得物理内存的使用效率更高,通常不是一个虚拟页面对应一个物理页面也是会有一定的重合,重合部分的页面映射两次,所以装载视图中每一Segment 的其实地址就不再必须是4096的倍数了。
  8. 一个进程在刚开始运行的时候,操作系统会预先把系统的环境变量和命令行参数传递到进程的堆栈(栈)中,在main函数开始执行的时候,main函数的两个参数args和argv[]两个参数就是从这里传递进来的,分别表示命令参数的数量和指向命令行传入参数的指针数组。
  9. ELF文件的装载过程: fork() -> execve() -> sys_execve()【系统调用,用于参数检查和复制】 -> do_execve()【读取文件头部的128字节,决定执行程序,如果第一行是#!则会解析这之后的字符串,以确定解释器的路径,例如#!/usr/bin/python】->load_elf_binary()->do_execve() -> sys_execve()【从内核态返回用户态】
  10. PE文件的装载过程:读取文件的第一页(段表,DOS文件头,PE文件头)-> 检查目标地址是否可用不可用则换一个装载地址(不可用一般只出现在dll的装载中)-> 按照段表一一装载各个段, 装载所以DLL -> 解析符号 -> 建立主线程并启动进程

第7章 动态链接

  1. 静态链接的缺点: 1). 内存和磁盘空间的浪费,(会在内存和磁盘中存在多份同一程序的拷贝),2). 程序开发和发布时不得不重新链接一遍所有文件,每次都需要用户下载新的连接之后的可执行文件
  2. 动态链接的优点:程序的可拓展性和兼容性,缺点:“DLL Hell"即由于dll文件接口的改变使得程序无法运行而这种错误事先难以得知, 还有由于在运行时链接所以会使得程序运行的速度相对变慢。
  3. 编译共享so文件的命令gcc -fPIC -shared -o Lib.so Lib.c, 共享目标文件so的装载地址是从0开始的,所以会在运行时确定地址。
  4. 静态共享库和静态链接库以及动态链接库都不同,本身属于动态库,没有被包含到一个可执行文件当中,但是它在运行时的地址是事先已经分配好的。
  5. 静态链接文件是链接时重定位,动态链接文件是装载时重定位,又叫基址重置;但是装载时重定位的一个大问题是无法实现多个进程的公用,解决办法是地址无关代码(PIC),先将将so文件分为四部分:1) 模块内部的函数调用 2) 模块内部的数据访问, 3) 模块外部的函数调用 4) 模块外部的数据访问。 编译器实际上没法知道一个函数或者变量是来自外部还是外部,所以编译器拓展 _declspec(dllimport)用于指定来自外部或者内部。
  6. 如何判断一个动态共享目标文件(DSO)是否是PIC的代码: readelf -d xx. so | grep TEXTREL如果没有任何输出则是PIC的,因为TEXTREL表示代码段重定位表地址,PIC不存在这个地址。
  7. 地址无关技术也可以用于可执行文件,即地址无关可执行文件(PIE)相应的GCC编译参数为-fPIE或-fpie.
  8. 为了防止DSO文件在运行时链接过程耗费太多的时间,采用延迟绑定(Lazy Binding)机制。即在第一次用到的时候进行地址绑定。
  9. 可执行文件动态链接的过程时,操作系统启动动态链接器,即加载ld.so文件并将控制权交给它,它将可执行文件需要的共享文件动态加载完之后,控制权再交给可执行文件。ELF文件的。interp段里面保存着一个字符串,这个字符串是动态链接器的路径,再linux下,几乎所有ELF文件的动态链接器的路径都是lib/ld.linux.so.2, 其他*nix系统可能会有差异, 这个路径是一个软链接,真正的文件是Glibc库的一部分,升级Glibc库也会升级动态链接器,但是软连接总是指向动态链接器文件,不需要手动修改。
  10. 动态链接文件中最重要的段时.dynamic段,类似于静态链接文件的ELF文件头,里面保存了依赖于那些共享对象,动态链接符号表的位置等等,ldd命令可以查看一个共享库依赖于哪些共享库。所依赖的库中linux.gate.so.1时一个在文件系统中不存在的文件,其加载地址在进程的内核区,
  11. 动态链接库中往往包含了两个表.dynsym 和.symtab。其中 .symtab保存了所有的符号,包括.dynsym中的符号,和静态链接的.symtab表类似,动态链接库也需要很多辅助的表,例如静态的符号字符串表.strtab 对应动态符号字符串表.dynstr 为了加快符号查找过程,还需要,符号哈希表 .hash可以用命令readelf -sD xx.so查看动态符号表和它的哈希表。
  12. 普通共享对象的链接和装载由动态链接器完成,但是动态链接器本身也是一个共享对象,所以要求动态链接器共享对象本身不依赖任何其他的共享对象,且其需要的全局变量和静态变量的重定位工作有它自己完成,对于第二个要求,需要一段精妙的代码完成,这被称为自举。

第七章7.6节以后略去不写

第八章

  1. 在开发共享库的时候,使用C的接口会让事情简单很多,因为C++非常复杂,支持模板等很多复杂操作,很容易破坏共享库的兼容性(ABI)
  2. 为了解决兼容性,共享库的命名采用libxxx.so.x.y.z其中x表示主版本号,y表示次版本号,z表示发布版本号,x表四重大升级,y表示增量升级,z表示对一些错误的修正和改进,相同的x和y,不同的z的共享库完全兼容,
  3. solaris和linux等系统中,会采用SO-NAME的方式解决存在多个相同功能的共享库的问题,SO-NAME时共享库的文件名.主版本号命名,例如,假如系统中存在libxxx.so.2.6.1和libxx.so.2.5.3则,在同目录下会存在一个名为libxx.so.2的软连接,并且指向最新版本的共享库libxx.so.2.6.1。在编译的时候,SO-NAME也会写入到共享库的.dynamic段中,防止写入完整名称之后遇到共享库升级而找不到的情况。
  4. 在linux中安装或更新一个共享库的时候需要运行ldconfig命令,它会自动将共享库目录中的软连接指向最新的共享库,对于新建的共享库则会新建软链接。
  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 程序员自我修养是一本技术类图书,通过以文字方式呈现,将核心内容以PDF文件的形式呈现给读者。 《程序员自我修养》一书是由俞甲子、俞甲子联合编写的,该书主要讲述了程序员在技术方面的自我提升与修养。书中详细介绍了程序员所需具备的技能与素质,并通过实例、案例等方式来进行详细解析。 首先,本书着重强调了程序员的技术素养。作为一名合格的程序员,必须具备扎实的编程基础知识,熟练掌握至少一种编程语言,并能够灵活应用于实际项目中。同时,还要不断学习新的编程技术和工具,提高开发效率和质量,不断追求技术的创新与突破。通过深入的技术讲解和实例分析,读者可以更好地理解和掌握这些关键技能。 其次,本书重视程序员的思维与方法。除了技术之外,合理的思维方式和解决问题的方法也是程序员必备的素养。本书通过探讨算法、数据结构、设计模式等内容,引导读者形成良好的编程思想和解决问题的思路。在实际开发过程中,程序员能够运用这些思维和方法,更加高效地解决实际问题。 此外,本书还提到了程序员的团队合作和沟通能力的重要性。现代软件开发往往需要多人合作完成,团队合作和沟通能力至关重要。本书通过讲解项目管理、代码规范、团队协作等方面的内容,帮助读者更好地适应团队开发的环境。 总之,《程序员自我修养》在技术、思维方式和团队合作等多个方面对程序员自我提升与修养进行了全面而详细的讲解。通过阅读文字版PDF,程序员可以更好地了解自身在技术和素养方面的不足,并通过实践和学习不断提升自己。 ### 回答2: 《程序员自我修养》是一本由俞甲子编写的程序员必读经典之一。这本书涵盖了计算机科学的基础知识和程序员在日常工作中所需要的修养和技能。 首先,这本书强调了程序员应具备的基本素质。不仅要有扎实的计算机基础知识,还要有广泛的知识储备和求知欲。书中指出,只有具备全面的知识背景,程序员才能适应不断变化的软件开发环境,并能够快速学习和掌握新的技术。 其次,书中提到了程序员的编程能力。编程是程序员的基本技能,而编程能力的提升不仅仅局限于语法和算法的掌握,更要关注代码的可维护性、可读性和可测试性。此外,书中还提到了代码风格规范、代码重构和代码调试等重要的编程技巧。 此外,这本书还介绍了程序员应具备的工程素养。程序员的工作不仅仅是写代码,还包括需求分析、架构设计、项目管理等方方面面。程序员应该具备良好的团队合作和沟通能力,能够与其他人合作完成一个项目。此外,书中还提到了软件工程的重要原则和方法,如模块化、面向对象设计、测试驱动开发等。 除此之外,书中还特别强调了程序员自我提升和学习能力。程序员应保持持续学习的态度,不断跟进行业的最新发展,并积极参与技术社区和开源项目,与其他程序员互动交流,共同进步。 总之,《程序员自我修养》是一本涵盖广泛知识和技能的书籍,其中介绍了程序员应具备的基本素质、编程能力、工程素养和自我提升等方面的内容。这本书对于程序员的职业发展和能力提升有着重要的指导作用,值得每位程序员认真阅读和实践。 ### 回答3: 《程序员自我修养》是一本由俞甲子编著的程序员修养指南,以PDF文字版的形式呈现。本书旨在帮助程序员们提升自己的理论基础和实践能力,进而追求个人的成长和职业发展。 《程序员自我修养》主要分为理论和实践两部分。在理论部分,作者深入浅出地介绍了计算机系统的基本原理、计算机网络的工作原理、软件工程中的常用设计模式等。通过这些理论知识的学习,程序员们能够更好地理解计算机系统的运行机制,从而编写更高效、稳定的程序。 而在实践部分,本书通过丰富的实例和案例,引导程序员们进行实践和项目开发。它包括了代码调试和优化的技巧、算法与数据结构的实践应用、多线程与并发编程的方法等。通过这些实践指导,程序员们能够更好地应对实际问题,并提高代码质量和效率。 《程序员自我修养文字版的PDF形式具有以下优点:一是方便携带和阅读,读者可以随时随地进行学习和查阅;二是易于搜索和标注,可以快速定位到自己关注的内容,并进行个性化的学习笔记;三是多平台兼容,可以在各种设备上进行阅读,满足不同读者的需求。 总之,《程序员自我修养文字版的PDF形式是一本帮助程序员们提升自己的重要工具,通过学习其中的理论知识和实践经验,程序员们能够更好地应对工作中的挑战,提升自身的竞争力,实现个人价值的最大化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值