[{"content":"“差生文具多”\u0026mdash;用积极消费来掩盖自己的懒惰 假努力\u0026mdash;用表象的勤奋来掩盖自己的懒惰 不要以战术上的勤奋掩饰战略上的懒惰\n","permalink":"http://note.leabol.top/posts/%E6%87%92%E6%83%B0/","summary":"\u003cp\u003e“差生文具多”\u0026mdash;用积极消费来掩盖自己的懒惰\n假努力\u0026mdash;用表象的勤奋来掩盖自己的懒惰\n不要以战术上的勤奋掩饰战略上的懒惰\u003c/p\u003e","title":"“差生文具多”"},{"content":"CS50群交流会感悟 时间与注意力 比起按照时间来算,用有效注意力来计算时间更加准确.想要提高效率,一味的追求时间上的长度,是不太明智的选择 日常生活中要有效的分配自己的精力,尽量不在没有的地方浪费宝贵的精力.\n当遇到瓶颈时,考虑三个方面 是否有足够的有效输入 是否有足够的有效输出 处理问题的核心能力不足\n平时要注意获取信息差 学校: 比赛 项目 活动 职场 : 行业现状 技术趋势 优质资源\n关于ACM竞赛 要综合自己的需求, 目标, 能力, 不要被周围同学学长给影响, 人云亦云 竞赛非常耗时间, 与cs课程往往不能兼顾\n大一阶段要特别注意培养自己的代码实现能力 趁着大一时间多, 多学一些\n现状 再简单的课能坚持下的人也是凤毛麟角 95%的人是\u0026rsquo;不学\u0026rsquo;的, 剩下又有80%是三天打鱼两天晒网的 行业 互联网的发展接近天花板, 公司开始\u0026quot;降本增效\u0026quot; ,新技术,新项目逐渐变少, 各公司开始稳定,裁员 ai行业 ,不需要大量算法人才, 而是技术的落地, 实现算力的提升, 需要的是高技术coding ai方向: 硬件(芯片, EDA软件, 车机系统) 与 软件(os,库,框架) 留意国外公司在做的事情 (MR), 国外ai发展领先国内一到两年 web开发 != CS, web开发用不到太多CS的知识 ","permalink":"http://note.leabol.top/posts/cs50%E7%BE%A4%E4%BA%A4%E6%B5%81%E4%BC%9A%E6%84%9F%E6%82%9F/","summary":"\u003ch1 id=\"cs50群交流会感悟\"\u003eCS50群交流会感悟\u003c/h1\u003e\n\u003ch3 id=\"时间与注意力\"\u003e时间与注意力\u003c/h3\u003e\n\u003cp\u003e比起按照时间来算,用有效注意力来计算时间更加准确.想要提高效率,一味的追求时间上的长度,是不太明智的选择\n日常生活中要有效的分配自己的精力,尽量不在没有的地方浪费宝贵的精力.\u003c/p\u003e\n\u003ch2 id=\"当遇到瓶颈时考虑三个方面\"\u003e当遇到瓶颈时,考虑三个方面\u003c/h2\u003e\n\u003cp\u003e是否有足够的有效输入\n是否有足够的有效输出\n处理问题的核心能力不足\u003c/p\u003e\n\u003ch2 id=\"平时要注意获取信息差\"\u003e平时要注意获取信息差\u003c/h2\u003e\n\u003cp\u003e学校: 比赛  项目  活动\n职场 : 行业现状  技术趋势 优质资源\u003c/p\u003e\n\u003ch2 id=\"关于acm竞赛\"\u003e关于ACM竞赛\u003c/h2\u003e\n\u003cp\u003e要综合自己的需求, 目标, 能力,  不要被周围同学学长给影响, 人云亦云\n竞赛非常耗时间, 与cs课程往往不能兼顾\u003c/p\u003e\n\u003ch2 id=\"大一阶段要特别注意培养自己的代码实现能力\"\u003e大一阶段要特别注意培养自己的代码实现能力\u003c/h2\u003e\n\u003cp\u003e趁着大一时间多, 多学一些\u003c/p\u003e\n\u003ch4 id=\"现状\"\u003e现状\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e再简单的课能坚持下的人也是\u003cstrong\u003e凤毛麟角\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e95%的人是\u0026rsquo;不学\u0026rsquo;的, 剩下又有80%是三天打鱼两天晒网的\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"行业\"\u003e行业\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e互联网的发展接近天花板, 公司开始\u0026quot;\u003cstrong\u003e降本增效\u003c/strong\u003e\u0026quot; ,新技术,新项目逐渐变少, 各公司开始稳定,裁员\u003c/li\u003e\n\u003cli\u003eai行业 ,不需要大量算法人才, 而是技术的落地, 实现算力的提升, 需要的是高技术coding\u003c/li\u003e\n\u003cli\u003eai方向: 硬件(芯片, EDA软件, 车机系统) 与 软件(os,库,框架)\u003c/li\u003e\n\u003cli\u003e留意国外公司在做的事情 (MR), 国外ai发展领先国内一到两年\u003c/li\u003e\n\u003cli\u003eweb开发 != CS, web开发用不到太多CS的知识\u003c/li\u003e\n\u003c/ul\u003e","title":"CS50群交流会感悟"},{"content":"理解Linux的file descriptor(文件描述符) ​\t我们知道在Linux系统中一切皆可以看成是文件，文件又可分为：普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候，我们每操作一次就找一次名字，这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引，这样要操作文件的时候，我们直接找到索引就可以对其进行操作了。\n​\t文件描述符（file descriptor）就是内核为了高效管理这些已经被打开的文件所创建的索引，其是一个非负整数（通常是小整数），用于指代被打开的文件，所有执行I/O操作的系统调用都通过文件描述符来实现。同时还规定系统刚刚启动的时候，0是标准输入，1是标准输出，2是标准错误。这意味着如果此时去打开一个新的文件，它的文件描述符会是3，再打开一个文件文件描述符就是4\u0026hellip;\u0026hellip;\nLinux内核对所有打开的文件有一个文件描述符表格，里面存储了每个文件描述符作为索引与一个打开文件相对应的关系，简单理解就是下图这样一个数组，文件描述符（索引）就是文件描述符表这个数组的下标，数组的内容就是指向一个个打开的文件的指针。\n文件描述符指向了由系统内核维护的一个file table中的某个条目(entry)。这个解释可能过于抽象，不过在正式详细介绍fd之前，有必要先了解用户程序和系统内核之间的工作过程。\n注: 本文描述的所有场景仅限于类unix系统环境，在windows中这玩意叫file handle(臭名昭著的翻译: 句柄)。\nUser space \u0026amp; Kernel space 现代操作系统会把内存划分为2个区域，分别为Use space(用户空间) 和 Kernel space(内核空间)。用户的程序在User space执行，系统内核在Kernel space中执行。\n用户的程序没有权限直接访问硬件资源，但系统内核可以。比如读写本地文件需要访问磁盘，创建socket需要网卡等。因此用户程序想要读写文件，必须要向内核发起读写请求，这个过程叫system call。\n内核收到用户程序system call时，负责访问硬件，并把结果返回给程序。\nFileInputStream fis = new FileInputStream(\u0026#34;/tmp/test.txt\u0026#34;); byte[] buf = new byte[256]; fis.read(buf); 上面代码的流程如下图所示\nFile Descriptor 上面简单介绍了User space和Kernel space，这对于理解fd有很大的帮助。fd会存在，就是因为用户程序无法直接访问硬件，因此当程序向内核发起system call打开一个文件时，在用户进程中必须有一个东西标识着打开的文件，这个东西就是fd。\nfile tables ​\t一个 Linux 进程启动后，会在内核空间中创建一个 PCB 控制块，PCB 内部有一个文件描述符表（File descriptor table），记录着当前进程所有可用的文件描述符，也即当前进程所有打开的文件。进程级的描述符表的每一条记录了单个进程所使用的文件描述符的相关信息，进程之间相互独立，一个进程使用了文件描述符3，另一个进程也可以用3。除了进程级的文件描述符表，系统还需要维护另外两张表：打开文件表、i-node 表。这两张表存储了每个打开文件的打开文件句柄（open file handle）。一个打开文件句柄存储了与一个打开文件相关的全部信息。\n和fd相关的一共有3张表，分别是file descriptor、file table、inode table，如下图所示。\nfile descriptors\nfile descriptors table由用户进程所有，每个进程都有一个这样的表，这里记录了进程打开的文件所代表的fd，fd的值映射到file table中的条目(entry)。\n另外，每个进程都会预留3个默认的fd: stdin、stdout、stderr;它们的值分别是0、1，2。\nInteger value Name symbolic constant file stream 0 Standard input STDIN_FILENO stdin 1 Standard output STDOUT_FILENO stdout 2 Standard error STDERR_FILENO stderr file table\nfile table是全局唯一的表，由系统内核维护。这个表记录了所有进程打开的文件的状态(是否可读、可写等状态)，同时它也映射到inode table中的entry。如下:\n当前文件偏移量（调用read()和write()时更新，或使用lseek()直接修改） 打开文件时的标识（open()的flags参数） 文件访问模式（如调用open()时所设置的只读模式、只写模式或读写模式） 与信号驱动相关的设置 对该文件i-node对象的引用，即i-node 表指针 inode table\ninode table同样是全局唯一的，它指向了真正的文件地址(磁盘中的位置)，每个entry全局唯一。内容如下:\n文件类型（例如：常规文件、套接字或FIFO）和访问权限 一个指针，指向该文件所持有的锁列表 文件的各种属性，包括文件大小以及与不同类型操作相关的时间戳 ​\t文件描述符、打开的文件句柄以及i-node之间的关系如下图：\n在进程 A 中，文件描述符 1 和 20 都指向了同一个打开文件表项，标号为 23（指向了打开文件表中下标为 23 的数组元素），这可能是通过调用 dup()、dup2()、fcntl() 或者对同一个文件多次调用了 open() 函数形成的。\n进程 A 的文件描述符 2 和进程 B 的文件描述符 2 都指向了同一个文件，这可能是在调用 fork() 后出现的（即进程 A、B 是父子进程关系），或者是不同的进程独自去调用 open() 函数打开了同一个文件，此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样。\n进程 A 的描述符 0 和进程 B 的描述符 3 分别指向不同的打开文件表项，但这些表项均指向 i-node 表的同一个条目（标号为 1976）；换言之，它们指向了同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了 open() 调用。同一个进程两次打开同一个文件，也会发生类似情况。\n这就说明：同一个进程的不同文件描述符可以指向同一个文件；不同进程可以拥有相同的文件描述符；不同进程的同一个文件描述符可以指向不同的文件（一般也是这样，除了 0、1、2 这三个特殊的文件）；不同进程的不同文件描述符也可以指向同一个文件。\n流程 当程序向内核发起system call open()，内核将会\n允许程序请求 创建一个entry插入到file table，并返回file descriptor 程序把fd插入到fds中。 当程序再次发起read()system call时，需要把相关的fd传给内核，内核定位到具体的文件(fd –\u0026gt; file table –\u0026gt; inode table)向磁盘发起读取请求，再把读取到的数据返回给程序处理。\n下面是read这个函数的定义，第一个参数fd即file descriptor。\nssize_t read(int fd, void *buf, size_t count); 同样的，writesystem call函数如下\nssize_t write(int fd, const void *buf, size_t nbytes); 从上面的结果来看，fd就是file table的一个索引，指向了file table中的entry。\n查看进程的file descriptors linux系统可以通过/proc/pid/fd文件夹查看进程的fd，比如我的redis进程id为96104，执行以下命令查看\nls -l /proc/96104/fd 参考 https://wiyi.org/linux-file-descriptor.html\nhttps://blog.csdn.net/yushuaigee/article/details/107883964\n","permalink":"http://note.leabol.top/posts/%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6/","summary":"\u003ch1 id=\"理解linux的file-descriptor文件描述符\"\u003e理解Linux的file descriptor(文件描述符)\u003c/h1\u003e\n\u003cp\u003e​\t\t我们知道在Linux系统中一切皆可以看成是文件，文件又可分为：普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候，我们每操作一次就找一次名字，这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引，这样要操作文件的时候，我们直接找到索引就可以对其进行操作了。\u003c/p\u003e\n\u003cp\u003e​\t\t\u003cstrong\u003e文件描述符\u003c/strong\u003e（file descriptor）就是内核为了高效管理这些已经被打开的文件所创建的\u003cstrong\u003e索引\u003c/strong\u003e，其是一个非负整数（通常是小整数），用于指代被打开的文件，所有执行I/O操作的系统调用都通过文件描述符来实现。同时还规定系统刚刚启动的时候，0是标准输入，1是标准输出，2是标准错误。这意味着如果此时去打开一个新的文件，它的文件描述符会是3，再打开一个文件文件描述符就是4\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://photo-lea.s3.bitiful.net/photo/01285b43579e17ec8f3d66c05b4e9165.png\"\u003e\u003c/p\u003e\n\u003cp\u003eLinux内核对所有打开的文件有一个文件描述符表格，里面存储了每个文件描述符作为索引与一个打开文件相对应的关系，简单理解就是下图这样一个数组，文件描述符（索引）就是文件描述符表这个数组的下标，数组的内容就是指向一个个打开的文件的指针。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e文件描述符\u003c/strong\u003e指向了由系统内核维护的一个file table中的某个条目(entry)。这个解释可能过于抽象，不过在正式详细介绍fd之前，有必要先了解用户程序和系统内核之间的工作过程。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e注: 本文描述的所有场景仅限于类unix系统环境，在windows中这玩意叫file handle(臭名昭著的翻译: 句柄)。\u003c/em\u003e\u003c/p\u003e\n\u003ch2 id=\"user-space--kernel-space\"\u003eUser space \u0026amp; Kernel space\u003c/h2\u003e\n\u003cp\u003e现代操作系统会把内存划分为2个区域，分别为Use space(用户空间) 和 Kernel space(内核空间)。用户的程序在User space执行，系统内核在Kernel space中执行。\u003c/p\u003e\n\u003cp\u003e用户的程序没有权限直接访问硬件资源，但系统内核可以。比如读写本地文件需要访问磁盘，创建socket需要网卡等。因此用户程序想要读写文件，必须要向内核发起读写请求，这个过程叫system call。\u003c/p\u003e\n\u003cp\u003e内核收到用户程序system call时，负责访问硬件，并把结果返回给程序。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c++\" data-lang=\"c++\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFileInputStream fis \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e FileInputStream(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/tmp/test.txt\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebyte[] buf \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e byte[\u003cspan style=\"color:#ae81ff\"\u003e256\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efis.read(buf);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e上面代码的流程如下图所示\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://photo-lea.s3.bitiful.net/photo/us_ks.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"file-descriptor\"\u003eFile Descriptor\u003c/h2\u003e\n\u003cp\u003e上面简单介绍了User space和Kernel space，这对于理解fd有很大的帮助。fd会存在，就是因为用户程序无法直接访问硬件，因此当程序向内核发起system call打开一个文件时，在用户进程中必须有一个东西标识着打开的文件，这个东西就是fd。\u003c/p\u003e\n\u003ch3 id=\"file-tables\"\u003efile tables\u003c/h3\u003e\n\u003cp\u003e​\t\t一个 Linux 进程启动后，会在内核空间中创建一个 PCB 控制块，PCB 内部有一个\u003cstrong\u003e文件描述符表\u003c/strong\u003e（File descriptor table），记录着当前进程所有可用的文件描述符，也即当前进程所有打开的文件。进程级的描述符表的每一条记录了单个进程所使用的文件描述符的相关信息，进程之间相互独立，一个进程使用了文件描述符3，另一个进程也可以用3。除了进程级的文件描述符表，系统还需要维护另外两张表：打开文件表、i-node 表。这两张表存储了每个打开文件的打开文件句柄（open file handle）。一个打开文件句柄存储了与一个打开文件相关的全部信息。\u003c/p\u003e\n\u003cp\u003e和fd相关的一共有3张表，分别是file descriptor、file table、inode table，如下图所示。\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"https://photo-lea.s3.bitiful.net/photo/103748658-67d36100-503f-11eb-960b-e77683e751f7.png\"\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003efile descriptors\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003efile descriptors table由用户进程所有，每个进程都有一个这样的表，这里记录了进程打开的文件所代表的fd，fd的值映射到file table中的条目(entry)。\u003c/p\u003e","title":"file descriptor"},{"content":"文件的10个关键系统调用 open/close read/write/lseek(随机查找) fstst(返回文件数据)/ftruncate(清空) unlink(删除文件)/mkdir / dup 文件系统的抽象 struct File { mode (permissions, type); size; user; group;//type数据结构的类型 timestamps(atime, mtime,ctime); content (bytes); }; map \u0026lt;string, File\u0026gt; // from file path to file 一种数据结构, 从路径到文件的映射\n","permalink":"http://note.leabol.top/posts/linux/","summary":"\u003ch2 id=\"文件的10个关键系统调用\"\u003e文件的10个关键系统调用\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eopen/close\u003c/li\u003e\n\u003cli\u003eread/write/lseek(随机查找)\u003c/li\u003e\n\u003cli\u003efstst(返回文件数据)/ftruncate(清空)\u003c/li\u003e\n\u003cli\u003eunlink(删除文件)/mkdir / dup\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"文件系统的抽象\"\u003e文件系统的抽象\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e File {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003emode\u003c/span\u003e (permissions, type); size; user; group;\u003cspan style=\"color:#75715e\"\u003e//type数据结构的类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\t\u003cspan style=\"color:#a6e22e\"\u003etimestamps\u003c/span\u003e(atime, mtime,ctime);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003econtent\u003c/span\u003e (bytes);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003emap \u0026lt;string, File\u0026gt;  // from file path  to file\n一种数据结构, 从路径到文件的映射\u003c/p\u003e","title":"linux"},{"content":"linux select函数 在Linux中，我们可以使用select函数实现I/O端口的复用，传递给 select函数的参数会告诉内核：\n我们所关心的文件描述符\n对每个描述符，我们所关心的状态。(我们是要想从一个文件描述符中读或者写，还是关注一个描述符中是否出现异常)\n我们要等待多长时间。(我们可以等待无限长的时间，等待固定的一段时间，或者根本就不等待)\n从 select函数返回后，内核告诉我们一下信息：\n对我们的要求已经做好准备的描述符的个数\n对于三种条件哪些描述符已经做好准备.(读，写，异常)\n有了这些返回信息，我们可以调用合适的I/O函数(通常是 read 或 write)，并且这些函数不会再阻塞.\n函数声明 #include \u0026lt;sys/select.h\u0026gt; int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout); 返回值：做好准备的文件描述符的个数，超时为0，错误为 -1.\n参数 struct timeval 首先我们先看一下最后一个参数。它指明我们要等待的时间：\nstruct timeval{ long tv_sec; /*秒 */ long tv_usec; /*微秒 */ } 有三种情况： timeout == NULL 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号， select函数将返回 -1,并将变量 erro设为 EINTR。\ntimeout-\u0026gt;tv_sec == 0 \u0026amp;\u0026amp;timeout-\u0026gt;tv_usec == 0不等待，直接返回。加入描述符集的描述符都会被测试，并且返回满足要求的描述符的个数。这种方法通过轮询，无阻塞地获得了多个文件描述符状态。\ntimeout-\u0026gt;tv_sec !=0 ||timeout-\u0026gt;tv_usec!= 0 等待指定的时间。当有描述符符合条件或者超过超时时间的话，函数返回。在超时时间即将用完但又没有描述符合条件的话，返回 0。对于第一种情况，等待也会被信号所中断。\nreadset, writset, exceptse 中间的三个参数 readset, writset, exceptset,指向描述符集。这些参数指明了我们关心哪些描述符，和需要满足什么条件(可写，可读，异常)。一个文件描述集保存在 fd_set 类型中。fd_set类型变量每一位代表了一个描述符。我们也可以认为它只是一个由很多二进制位构成的数组。如下图所示：\nfd_set类型 对于 fd_set类型的变量我们所能做的就是声明一个变量，为变量赋一个同种类型变量的值，或者使用以下几个宏来控制它：\n#include \u0026lt;sys/select.h\u0026gt; int FD_ZERO(int fd, fd_set *fdset); int FD_CLR(int fd, fd_set *fdset); int FD_SET(int fd, fd_set *fd_set); int FD_ISSET(int fd, fd_set *fdset); FD_ZERO宏将一个 fd_set类型变量的所有位都设为 0，使用FD_SET将变量的某个位置位。清除某个位时可以使用 FD_CLR，我们可以使用 FD_ISSET来测试某个位是否被置位。\n当声明了一个文件描述符集后，必须用FD_ZERO将所有位置零。之后将我们所感兴趣的描述符所对应的位置位，操作如下：\nfd_set rset; int fd; FD_ZERO(\u0026amp;rset); FD_SET(fd, \u0026amp;rset); FD_SET(stdin, \u0026amp;rset); select返回后，用FD_ISSET测试给定位是否置位：\nif(FD_ISSET(fd, \u0026amp;rset) { ... } 具体解释select的参数： （1）intmaxfdp是一个整数值，是指集合中所有文件描述符的范围，即所有文件描述符的最大值加1，不能错。\n说明：对于这个原理的解释可以看上边fd_set的详细解释，fd_set是以位图的形式来存储这些文件描述符。maxfdp也就是定义了位图中有效的位的个数。\n（2）fd_set*readfds是指向fd_set结构的指针，这个集合中应该包括文件描述符，我们是要监视这些文件描述符的读变化的，即我们关心是否可以从这些文件中读取数据了，如果这个集合中有一个文件可读，select就会返回一个大于0的值，表示有文件可读；如果没有可读的文件，则根据timeout参数再判断是否超时，若超出timeout的时间，select返回0，若发生错误返回负值。可以传入NULL值，表示不关心任何文件的读变化。\n（3）fd_set*writefds是指向fd_set结构的指针，这个集合中应该包括文件描述符，我们是要监视这些文件描述符的写变化的，即我们关心是否可以向这些文件中写入数据了，如果这个集合中有一个文件可写，select就会返回一个大于0的值，表示有文件可写，如果没有可写的文件，则根据timeout参数再判断是否超时，若超出timeout的时间，select返回0，若发生错误返回负值。可以传入NULL值，表示不关心任何文件的写变化。\n（4）fd_set*errorfds同上面两个参数的意图，用来监视文件错误异常文件。\n（5）structtimeval* timeout是select的超时时间，这个参数至关重要，它可以使select处于三种状态，第一，若将NULL以形参传入，即不传入时间结构，就是将select置于阻塞状态，一定等到监视文件描述符集合中某个文件描述符发生变化为止；第二，若将时间值设为0秒0毫秒，就变成一个纯粹的非阻塞函数，不管文件描述符是否有变化，都立刻返回继续执行，文件无变化返回0，有变化返回一个正值；第三，timeout的值大于0，这就是等待的超时时间，即 select在timeout时间内阻塞，超时时间之内有事件到来就返回了，否则在超时后不管怎样一定返回，返回值同上述。\n说明：\n函数返回：\n（1）当监视的相应的文件描述符集中满足条件时，比如说读文件描述符集中有数据到来时，内核(I/O)根据状态修改文件描述符集，并返回一个大于0的数。\n（2）当没有满足条件的文件描述符，且设置的timeval监控时间超时时，select函数会返回一个为0的值。\n（3）当select返回负值时，发生错误。\n理解select模型 理解select模型的关键在于理解fd_set,为说明方便，取fd_set长度为1字节，fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。\n（1）执行fd_set set;FD_ZERO(\u0026amp;set);则set用位表示是0000,0000。\n（2）若fd＝5,执行FD_SET(fd,\u0026amp;set);后set变为0001,0000(第5位置为1)\n（3）若再加入fd＝2，fd=1,则set变为0001,0011\n（4）执行select(6,\u0026amp;set,0,0,0)阻塞等待\n（5）若fd=1,fd=2上都发生可读事件，则select返回，此时set变为0000,0011。注意：没有事件发生的fd=5被清空。\n基于上面的讨论，可以轻松得出select模型的特点：\n（1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务器上sizeof(fd_set)＝512，每bit表示一个文件描述符，则我服务器上支持的最大文件描述符是512*8=4096。据说可调，另有说虽然可调，但调整上限受于编译内核时的变量值。\n（2）将fd加入select监控集的同时，还要再使用一个数据结构array保存放到select监控集中的fd，一是用于再select返回后，array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空，则每次开始 select前都要重新从array取得fd逐一加入（FD_ZERO最先），扫描array的同时取得fd最大值maxfd，用于select的第一个参数。\n（3）可见select模型必须在select前循环array（加fd，取maxfd），select返回后循环array（FD_ISSET判断是否有时间发生）。\n","permalink":"http://note.leabol.top/posts/linux-select%E5%87%BD%E6%95%B0/","summary":"\u003ch1 id=\"linux-select函数\"\u003elinux select函数\u003c/h1\u003e\n\u003cp\u003e在Linux中，我们可以使用select函数实现I/O端口的复用，传递给 select函数的参数会告诉内核：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e我们所关心的文件描述符\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对每个描述符，我们所关心的状态。(我们是要想从一个文件描述符中读或者写，还是关注一个描述符中是否出现异常)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我们要等待多长时间。(我们可以等待无限长的时间，等待固定的一段时间，或者根本就不等待)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e从 select函数返回后，内核告诉我们一下信息：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e对我们的要求已经做好准备的描述符的个数\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e对于三种条件哪些描述符已经做好准备.(读，写，异常)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有了这些返回信息，我们可以调用合适的I/O函数(通常是 read 或 write)，并且这些函数不会再阻塞.\u003c/p\u003e\n\u003ch2 id=\"函数声明\"\u003e函数声明\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;sys/select.h\u0026gt;   \u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eselect\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e maxfdp1, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ereadset, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ewriteset, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eexceptset,\u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e timeval \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003etimeout);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e返回值\u003c/strong\u003e：做好准备的文件描述符的个数，超时为0，错误为 -1.\u003c/p\u003e\n\u003ch2 id=\"参数\"\u003e参数\u003c/h2\u003e\n\u003ch3 id=\"struct-timeval\"\u003estruct timeval\u003c/h3\u003e\n\u003cp\u003e首先我们先看一下最后一个参数。它指明我们要等待的时间：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e timeval{   \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e tv_sec;  \u003cspan style=\"color:#75715e\"\u003e/*秒 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e tv_usec; \u003cspan style=\"color:#75715e\"\u003e/*微秒 */\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"有三种情况\"\u003e有三种情况：\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003etimeout == NULL\u003c/strong\u003e 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号， select函数将返回 -1,并将变量 erro设为 EINTR。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003etimeout-\u0026gt;tv_sec == 0 \u0026amp;\u0026amp;timeout-\u0026gt;tv_usec == 0\u003c/strong\u003e不等待，直接返回。加入描述符集的描述符都会被测试，并且返回满足要求的描述符的个数。这种方法通过轮询，无阻塞地获得了多个文件描述符状态。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003etimeout-\u0026gt;tv_sec !=0 ||timeout-\u0026gt;tv_usec!= 0\u003c/strong\u003e 等待指定的时间。当有描述符符合条件或者超过超时时间的话，函数返回。在超时时间即将用完但又没有描述符合条件的话，返回 0。对于第一种情况，等待也会被信号所中断。\u003c/p\u003e\n\u003ch3 id=\"readset-writset-exceptse\"\u003ereadset, writset, exceptse\u003c/h3\u003e\n\u003cp\u003e中间的三个参数 readset, writset, exceptset,指向描述符集。这些参数指明了我们关心哪些描述符，和需要满足什么条件(可写，可读，异常)。一个文件描述集保存在 fd_set 类型中。fd_set类型变量每一位代表了一个描述符。我们也可以认为它只是一个由很多二进制位构成的数组。如下图所示：\u003c/p\u003e","title":"linux select函数"},{"content":"Makefile 是 make 工具的配置文件，主要用于定义如何构建和管理项目的编译过程。Makefile 是 C/C++ 编译项目中的重要工具，尤其在多文件、多模块的项目中，为了方便复杂项目的管理，可以通过自动化规则提高编译效率。\n这篇文章是 Makefile 的入门教程的介绍，包括其基本语法、常用功能、以及实际使用中的高级技巧。\nMakefile 的基本概念 安装 make：\nsudo apt-get update sudo apt-get install make 核心功能 自动化编译：根据文件的依赖关系自动决定哪些文件需要重新编译。 提高效率：只编译发生变化的部分。 多任务支持：可以定义清理、打包、测试等任务。 使用方法 运行make命令时，默认会读取当前目录下的Makefile 文件。\nmake # 执行默认的目标 make \u0026lt;target\u0026gt; # 执行指定的目标 例如：\nmake clean # 执行 \u0026#34;clean\u0026#34; 目标 Makefile 的基本语法 1. 目标语法 Makefile 的基本语法如下：\ntarget: prerequisites commands target：目标文件或命令名称。例如可执行文件、目标文件或任务名称。 prerequisites：依赖文件或其他目标。只有依赖文件发生变化时，target 才会被重新生成。 commands：生成目标的命令（必须以 Tab 开头）。 示例：\nhello: hello.o gcc -o hello hello.o hello.o: hello.c gcc -c hello.c 在示例代码中：\n如果 hello.c 被修改，则 hello.o 会重新生成。\n如果 hello.o 被修改，则 hello 会重新生成。\n2. 变量定义 Makefile 支持变量定义，用于简化配置和重复的命令。\n示例1：\nCC = gcc CFLAGS = -Wall -g # 简单赋值 CC :=$(XX) gcc 当前有效 // 立马获取当前XX变量的值 # 递归赋值 CC =$(XX) gcc\t// 去递归寻找XX变量的最后一个值 # 条件赋值 CC ?= gcc\t// 如果有CC变量，则该语句无效 # 追加赋值 CC +=$(XX) gcc\t// 在原来值的基础上，进行追加 # 使用：$(CC) 获取变量的值 示例2：\nx := jake y := $(x) and rose x := tonly all : echo \u0026#34;x=$(x),y=$(y)\u0026#34; 使用变量（示例1）\nhello: hello.o $(CC) $(CFLAGS) -o hello hello.o 输出：（示例2）\nx=windx,y=jake and rose 示例\nCC = gcc CFLAGS = -Wall -O2 hello: hello.o $(CC) $(CFLAGS) -o hello hello.o hello.o: hello.c $(CC) $(CFLAGS) -c hello.c 3. 内置变量 Makefile 提供了一些常用的内置变量，可以减少重复工作。\n变量 | 功能\n变量 功能 $@ 当前目标的名称（target）。 $\u0026lt; 第一个依赖文件的名称（prerequisite）。 $^ 所有依赖文件的名称。 代码片：\nCC = gcc CFLAGS = -Wall -g hello: hello.o $(CC) $(CFLAGS) -o $@ $^ 在这里：\n$@ 是 hello（目标）。 $^ 是 hello.o（所有依赖文件）。 4. 通配符和自动化规则 Makefile 支持通配符和模式匹配规则，用于简化多文件项目的编写。\n通配符\n*.c：匹配所有 .c 文件。 $(wildcard *.c)：列出当前目录下所有 .c 文件。 $(patsubst %.c, %.o, $(wildcard *.c))：将所有 .c 文件替换为对应的 .o 文件。 自动化规则\n使用模式规则可以自动生成目标文件：\n%.o: %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $@ 表示所有 .o 文件都可以由对应的 .c 文件生成。 代码：\nCC = gcc CFLAGS = -Wall -O0 -g SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC)) hello: $(OBJ) $(CC) $(CFLAGS) -o $@ $^ %.o: %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $@ 5. 伪目标 伪目标（phony targets）是指不生成实际文件的目标，通常用于清理、测试等任务。\n伪目标也是一个目标，该目标不需要生成，每一次去执行该目标，都会执行。\n定义伪目标：\n.PHONY: clean # 将当前目标设定为伪目标，每次执行该目标都会执行命令 clean: rm -f *.o hello 使用 .PHONY 声明可以避免冲突（例如当前目录下存在名为 clean 的文件时）。 6. 自动推导规则 在使用make编译.c源文件时，可以省略编译一个.c文件所使用的命令。这是因为make存在一个默认的规则，能够自动完成对.c文件的编译并生成对应的.o文件。它执行命令“cc -c”来编译.c源文件。对于上边的例子，此默认规则就使用命令“cc -c main.c -o main.o”来创建文件“main.o”。因此对一个目标文件是“N.o”，倚赖文件是“N.c”的规则。可以省略其规则的命令行，使用 make 的默认命令。此默认规则称为make的隐含规则（关于隐含规则可查看我上传至资源中的 《GUN make中文手册》第九章 [ 使用隐含规则 ] 一章，有详细说明。）\n我们书写 Makefile 时，对于一个.c文件如果使用 make 的隐含规则，那么它会被自动作为对应.o文件的一个依赖文件（对应是指：文件名除后缀外，其余都相同的两个文件）。因此我们也可以在规则中省略目标的倚赖.c文件。\n自动推导规则_1\n自动推导规则_2\n我们可以看见，当app文件被创建之后，再次执行 make 命令时，提示：make: 'app' is up to date.，此处是 make 的时间戳管理方式，如果目标生成的时间 晚于 依赖，该目标是最新的，那么该目标就不需要再编译重新生成。（如果想详细了解makefile的时间戳管理机制，可以点击查看这篇文章，对 Makefile 的时间戳管理机制有更详细的说明。\u0026lt;\n笨猫猫的小茶馆：Makefile 时间戳管理2 赞同 · 0 评论文章\n）\n项目示例 这是一个多文件 C 项目的示例 Makefile：\n项目目录 project/ ├── main.c ├── utils.c ├── utils.h ├── Makefile ``` ##### Makefile ```bash # 编译器和编译参数 CC = gcc CFLAGS = -Wall -g # 源文件和目标文件 SRC = main.c utils.c OBJ = $(SRC:.c=.o) TARGET = my_program # 默认目标 all: $(TARGET) # 链接目标文件 $(TARGET): $(OBJ) $(CC) $(CFLAGS) -o $@ $^ # 编译规则（自动化规则） %.o: %.c $(CC) $(CFLAGS) -c $\u0026lt; -o $@ # 清理目标 .PHONY: clean clean: rm -f $(OBJ) $(TARGET) 运行说明 构建项目 make 清理项目： make clean 这么写缺失中间的流程，接下来我结合图片将 makefile 管理项目的实际流程走一遍：\n要求：（虽然是简易版用于教学的，但其中的过程和项目管理的思路，即使在大型项目中也是一致的，不同的只是划分的层级结构、架构更为复杂而已。）\n创建项目目录 include/project.h 集合的头文件 jack 文件夹下的文件 将 jack.c 通过编译生成 jack.o 文件 ——\u0026gt; 然后将 jack.o 放入 obj 文件夹下 此处的Makefile用于管理main.c文件，将main.c编译转化为main.o，将其保存在obj文件夹下统一管理 main.o文件生成成功并放在了统一文件夹obj下，接下来，将main.o和jack.o做链接操作生成app文件，因此，我们需要在obj文件夹下创建Makefile文件，用于将所有集合在此处的.0 文件链接生成可执行文件app 成功生成了可执行文件app 因为main :会自动寻址至依赖的第一个文件，结果将提示文件已存在。所以这里我们要将需要生成的文件 main 设为伪目标。 至此，前面的步骤我们共计完成了 4 步：\n第一步，我们将 jack 文件夹下的 jack.c 生成了 jack.o ，将其放在 obj 文件夹下；\n第二步，我们将 main 文件夹下的 main.c 生成了 main.o，将其放在 obj 文件夹下；\n第三步，在 obj 文件夹下，将这里所有集合着的 .o 文件 最终生成了 可执行文件 app。\n最后，我们在整个项目目录下，生成一个 Makefile 文件，用于管理整个项目，这样，最终我们只需要 make 一次，便能够得到整体项目的可执行文件，而不需要经过上述如此繁琐的步骤。\nmake -C 文件夹/[目标] // 去到该文件夹下 去执行该文件夹下的 Makefile 的 第一个目标[目标] 因为第一个目标已存在，所以此处我们需要提前设置mainclean为伪目标。\n最终生成可执行文件 app 优化 Makefile 代码。 添加共享变量，在最终的 Makefile 文件中添加共享变量，这样的话，可供同一级目录 和 该目录下的所有子目录中的 Makefile 文件皆可以共享到最上层的 Makefile文件 中的共享变量。 export 共享变量 // 当前同一级目录下的子目录都可以共享该变量 这时候进入了一个新人，分配任务给 rose，创建 rose 文件夹并加入这部分模块的代码， 至此，以上为 Makefile 项目管理在开发中的实际应用（简易版）。\n高级功能 条件判断 根据条件设置变量或执行不同的规则。\nDEBUG = 1 ifeq ($(DEBUG), 1) CFLAGS += -g else CFLAGS += -O2 endif 包含其他 Makefile 使用 include 将多个 Makefile 文件整合在一起。\ninclude common.mk 这种方式适合大型项目，将公共配置提取到单独的文件中。 一些常见问题与技巧 如何调试 Makefile？ 运行 make 时加上-n或--dry-run参数，可以查看执行的命令而不真正运行：\nmake -n 如何提高编译效率？ 使用 make 的并行编译选项-j，可以同时编译多个目标：\nmake -j4 其中 4 表示最多允许 4 个任务同时执行。 综上。这篇文章仅仅只介绍了 makefile 的简单用法，更多更详细的内容可以下载资源查看 makefile 手册（中文版），Makefile 是一个强大的工具，适合用于管理从简单到复杂的编译流程。\n本章主要介绍了：\n基础语法：理解目标、依赖和命令的结构。 变量和内置变量：使用变量提高可读性和灵活性。 自动化规则：使用通配符和模式规则减少重复代码。 伪目标：定义清理、测试等任务。 高级功能：条件判断、多文件组织、并行编译。 通过不断优化 Makefile，可以显著提高项目的管理效率和可维护性，适合运用和管理大型项目。\n以上。仅供学习与分享交流，请勿用于商业用途！转载需提前说明。\n","permalink":"http://note.leabol.top/posts/makefile/","summary":"\u003cp\u003e\u003cstrong\u003eMakefile\u003c/strong\u003e 是 make 工具的配置文件，主要用于定义如何构建和管理项目的编译过程。Makefile 是 C/C++ 编译项目中的重要工具，尤其在多文件、多模块的项目中，为了方便复杂项目的管理，可以通过自动化规则提高编译效率。\u003c/p\u003e\n\u003cp\u003e这篇文章是 Makefile 的入门教程的介绍，包括其基本语法、常用功能、以及实际使用中的高级技巧。\u003c/p\u003e\n\u003ch3 id=\"makefile-的基本概念\"\u003eMakefile 的基本概念\u003c/h3\u003e\n\u003cp\u003e安装 \u003ccode\u003emake\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get update\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get install make\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"核心功能\"\u003e核心功能\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://zhida.zhihu.com/search?content_id=707902769\u0026amp;content_type=Answer\u0026amp;match_order=1\u0026amp;q=%E8%87%AA%E5%8A%A8%E5%8C%96%E7%BC%96%E8%AF%91\u0026amp;zhida_source=entity\"\u003e自动化编译\u003c/a\u003e：根据文件的依赖关系自动决定哪些文件需要重新编译。\u003c/li\u003e\n\u003cli\u003e提高效率：只编译发生变化的部分。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhida.zhihu.com/search?content_id=707902769\u0026amp;content_type=Answer\u0026amp;match_order=1\u0026amp;q=%E5%A4%9A%E4%BB%BB%E5%8A%A1%E6%94%AF%E6%8C%81\u0026amp;zhida_source=entity\"\u003e多任务支持\u003c/a\u003e：可以定义清理、打包、测试等任务。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"使用方法\"\u003e使用方法\u003c/h3\u003e\n\u003cp\u003e运行\u003ccode\u003emake\u003c/code\u003e命令时，默认会读取当前目录下的\u003cstrong\u003eMakefile 文件\u003c/strong\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake            \u003cspan style=\"color:#75715e\"\u003e# 执行默认的目标\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake \u0026lt;target\u0026gt;   \u003cspan style=\"color:#75715e\"\u003e# 执行指定的目标\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e例如：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake clean      \u003cspan style=\"color:#75715e\"\u003e# 执行 \u0026#34;clean\u0026#34; 目标\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"makefile-的基本语法\"\u003eMakefile 的基本语法\u003c/h3\u003e\n\u003ch3 id=\"1-目标语法\"\u003e1. 目标语法\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eMakefile\u003c/strong\u003e 的基本语法如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etarget: prerequisites\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tcommands\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003etarget\u003c/strong\u003e：目标文件或命令名称。例如可执行文件、目标文件或任务名称。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eprerequisites\u003c/strong\u003e：依赖文件或其他目标。只有依赖文件发生变化时，target 才会被重新生成。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ecommands\u003c/strong\u003e：生成目标的命令（必须以 \u003cstrong\u003eTab\u003c/strong\u003e 开头）。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e示例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehello: hello.o\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tgcc -o hello hello.o\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehello.o: hello.c\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tgcc -c hello.c\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在示例代码中：\u003c/p\u003e","title":"Makefile 的基本概念"},{"content":" 更新包管理器：\n对于Ubuntu/Debian： sudo apt update 安装MySQL Server：\n对于Ubuntu/Debian： sudo apt install mysql-server 启动MySQL服务：\n对于Ubuntu/Debian： sudo systemctl start mysql 设置root密码：\n运行以下命令： sudo mysql_secure_installation 验证安装：\n运行以下命令登录MySQL： mysql -u root -p ","permalink":"http://note.leabol.top/posts/%E5%AE%89%E8%A3%85mysql/","summary":"\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e更新包管理器\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e对于Ubuntu/Debian：\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt update\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e安装MySQL Server\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e对于Ubuntu/Debian：\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt install mysql-server\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e启动MySQL服务\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e对于Ubuntu/Debian：\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo systemctl start mysql\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e设置root密码\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e运行以下命令：\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo mysql_secure_installation\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e验证安装\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e运行以下命令登录MySQL：\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emysql -u root -p\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e","title":"MySQL"},{"content":"为什么Lisp语言如此先进?\n一个前辈的官网\n","permalink":"http://note.leabol.top/posts/%E4%B8%80%E4%BA%9B%E7%BD%91%E7%AB%99/","summary":"\u003cp\u003e\u003ca href=\"https://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html\"\u003e为什么Lisp语言如此先进?\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://norvig.com/\"\u003e一个前辈的官网\u003c/a\u003e\u003c/p\u003e","title":"一些网站"},{"content":"为什么叫补码(Two\u0026rsquo;s complement) 计算机的加减法运算天生是一个模2^N的同余类上的运算，满2^N会抛弃进位，那表示有符号数时使用同余类代表很正常吧，比如-1 = 2^N -1 (mod 2^N)，-2 = 2^N-2 (mod 2^N)，这实际上就是补码了。\n","permalink":"http://note.leabol.top/posts/%E5%8E%9F%E7%A0%81-%E5%8F%8D%E7%A0%81%E5%92%8C%E8%A1%A5%E7%A0%81/","summary":"\u003ch3 id=\"为什么叫补码twos-complement\"\u003e为什么叫补码(Two\u0026rsquo;s complement)\u003c/h3\u003e\n\u003cp\u003e计算机的加减法运算天生是一个\u003ca href=\"https://zhida.zhihu.com/search?content_id=190505781\u0026amp;content_type=Answer\u0026amp;match_order=1\u0026amp;q=%E6%A8%A12%5EN\u0026amp;zhida_source=entity\"\u003e模2^N\u003c/a\u003e的\u003ca href=\"https://zhida.zhihu.com/search?content_id=190505781\u0026amp;content_type=Answer\u0026amp;match_order=1\u0026amp;q=%E5%90%8C%E4%BD%99%E7%B1%BB\u0026amp;zhida_source=entity\"\u003e同余类\u003c/a\u003e上的运算，满2^N会抛弃进位，那表示有符号数时使用同余类代表很正常吧，比如-1 = 2^N -1 (mod 2^N)，-2 = 2^N-2 (mod 2^N)，这实际上就是\u003ca href=\"https://zhida.zhihu.com/search?content_id=190505781\u0026amp;content_type=Answer\u0026amp;match_order=1\u0026amp;q=%E8%A1%A5%E7%A0%81\u0026amp;zhida_source=entity\"\u003e补码\u003c/a\u003e了。\u003c/p\u003e","title":"为什么叫补码"},{"content":"关于位图存储与数组下标存储的探讨 最近在看《编程珠玑》，书中的第一章提到了位图。位图存储使用二进制位的位数信息，来表示数字。例如，存储1、3、4、6、8，这五个数字， 可以使用\u0026lt;1, 0, 1, 1, 0, 1, 0, 1\u0026gt;这样的向量来表示，这样可以大大减少存储空间， 只用了一个字节（8bit），就可以存储原来需要的8个数字才能表示的信息。\n当我跟朋友谈到这个方法时，他却产生了质疑，他觉得这样不如直接按照数组下标存储来的快。他认为数组下标直接存储，直接一步完成，二位图则需要每次位运算寻址，会非常费时间。于是我们就决定写一个程序，实际跑一下看看。\n这是位图的代码\ntypedef struct { uint32_t *bits; size_t size; } Bitmap; Bitmap *create_bitmap(size_t max_num) { size_t num_words = (max_num + 31) / 32; // 计算需要多少个32位字 Bitmap *bm = malloc(sizeof(Bitmap)); if (!bm) { perror(\u0026#34;Bitmap allocation failed\u0026#34;); exit(EXIT_FAILURE); } bm-\u0026gt;bits = calloc(num_words, sizeof(uint32_t)); // 分配约 1亿位 ≈ 12.5MB bm-\u0026gt;size = max_num; if (!bm-\u0026gt;bits) { perror(\u0026#34;Bitmap bits allocation failed\u0026#34;); exit(EXIT_FAILURE); } return bm; } void bitmap_set(Bitmap *bm, int num) { size_t word_idx = num / 32; size_t bit_idx = num % 32; bm-\u0026gt;bits[word_idx] |= (1U \u0026lt;\u0026lt; bit_idx); } int bitmap_get(const Bitmap *bm, int num) { size_t word_idx = num / 32; size_t bit_idx = num % 32; return (bm-\u0026gt;bits[word_idx] \u0026gt;\u0026gt; bit_idx) \u0026amp; 1U; } 位运算把每个字节大小的内存当作为一组，使用除法判断组数， 再用对8取余，得出每组的位次\n下面是数组的代码\n#define N 10000000 // 处理 1000 万个整数 #define MAX_NUM 100000000 // 数字范围：0 ~ 1亿 void array_set(int *arr, int num) { arr[num] = 1; } int array_get(const int *arr, int num) { return arr[num]; } // 初始化数组（全部置0） int *create_array() { int *arr = calloc(MAX_NUM, sizeof(int)); // 分配 1亿个int ≈ 400MB if (!arr) { perror(\u0026#34;Array allocation failed\u0026#34;); exit(EXIT_FAILURE); } return arr; } 结果确实出乎了我们的意料，总结来说如下\n当数据导向在大小在10MB一下时， 数组比位图略有优势 当数据大于10MB时， 位图大约要快5-10倍 然而当数据非常大时，比如1一个数， 虽然位图还是要快于数组，但两者没那么明显了 这是因为\n在很小数据的时候，cpu缓存可以完全存下数据，而数组的指令开销更少，所以会略快 而当数据在大时，数组就无法在缓存中完全存储了，而位图还可以。于是cpu的缓存命中率就会下降，cpu需要从内存中加载数据，我们都知道cpu缓存的速度比内存快几十倍，所以数组方式的就慢了很多 但是当数据非常大时， 这时位图也无法完全缓存了，在这种情况下，影响程序运行速度的主要因素就是从内存加载的速度了，这时候两者时间接近。但是位图的存储更加紧凑，命中概率更高，所以还是会快一些。 何时选择哪种方案？ 用数组： 当数字范围小（例如 0~1000），或需要频繁读取且容忍内存浪费时。\n用位图： 当处理海量数据（如爬虫去重、数据库索引），或数字范围大但稀疏分布时。\n实际应用案例： Linux 内核页表 使用位图管理内存页 Redis 的 Bitmap 类型 用于高效存储布尔值 总结 实践是检验真理的唯一标准 我们对于计算机的了解不足，忘记了计算机是一个复杂的系统，程序运行的时间受到多种因素影响。而我们都以理想的角度去理解，就导致了形而上学的认识。\n收获 认识到了cpu缓存命中带来的影响 对不同数据结构在不同条件下的性能影响 ","permalink":"http://note.leabol.top/posts/%E5%85%B3%E4%BA%8E%E4%BD%8D%E5%9B%BE%E5%AD%98%E5%82%A8%E4%B8%8E%E6%95%B0%E7%BB%84%E4%B8%8B%E6%A0%87%E5%AD%98%E5%82%A8%E7%9A%84%E6%8E%A2%E8%AE%A8/","summary":"\u003ch1 id=\"关于位图存储与数组下标存储的探讨\"\u003e关于位图存储与数组下标存储的探讨\u003c/h1\u003e\n\u003cp\u003e最近在看《编程珠玑》，书中的第一章提到了位图。位图存储使用二进制位的位数信息，来表示数字。例如，存储1、3、4、6、8，这五个数字， 可以使用\u0026lt;1, 0, 1, 1, 0, 1, 0, 1\u0026gt;这样的向量来表示，这样可以大大减少存储空间， 只用了一个字节（8bit），就可以存储原来需要的8个数字才能表示的信息。\u003c/p\u003e\n\u003cp\u003e当我跟朋友谈到这个方法时，他却产生了质疑，他觉得这样不如直接按照数组下标存储来的快。他认为数组下标直接存储，直接一步完成，二位图则需要每次位运算寻址，会非常费时间。于是我们就决定写一个程序，实际跑一下看看。\u003c/p\u003e\n\u003cp\u003e这是位图的代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etypedef\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003euint32_t\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ebits;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e size;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} Bitmap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBitmap \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003ecreate_bitmap\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e max_num) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e num_words \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (max_num \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e31\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e;  \u003cspan style=\"color:#75715e\"\u003e// 计算需要多少个32位字\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    Bitmap \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ebm \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emalloc\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(Bitmap));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003ebm) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eperror\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bitmap allocation failed\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eexit\u003c/span\u003e(EXIT_FAILURE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bm\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003ebits \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecalloc\u003c/span\u003e(num_words, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003euint32_t\u003c/span\u003e));  \u003cspan style=\"color:#75715e\"\u003e// 分配约 1亿位 ≈ 12.5MB\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e    bm\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003esize \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e max_num;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003ebm\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003ebits) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eperror\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Bitmap bits allocation failed\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eexit\u003c/span\u003e(EXIT_FAILURE);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e bm;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebitmap_set\u003c/span\u003e(Bitmap \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ebm, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e num) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e word_idx \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e bit_idx \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bm\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003ebits[word_idx] \u003cspan style=\"color:#f92672\"\u003e|=\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1U\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e bit_idx);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebitmap_get\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e Bitmap \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ebm, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e num) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e word_idx \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e bit_idx \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e num \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e32\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e (bm\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003ebits[word_idx] \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e bit_idx) \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1U\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e位运算把每个字节大小的内存当作为一组，使用除法判断组数， 再用对8取余，得出每组的位次\u003c/p\u003e","title":"关于位图存储与数组下标存储的探讨"},{"content":"基础算法归纳 #cs #c #算法\n输出最大值 #include \u0026lt;stdio.h\u0026gt; int main(void) { int i[3], max; scanf(\u0026#34;%d %d %d\u0026#34;, \u0026amp;i[0], \u0026amp;i[1], \u0026amp;i[2]);//通过数组来代替不同变量 max = i[0]; for (int j = 1; j \u0026lt; n; j++) { if (max \u0026lt; i[j]) { max = i[j]; } } printf(\u0026#34;%d\u0026#34;, max); } 冒泡排序 void BubbleSort(int arr[], int n)//arr[] 在c中要用第一个数组值 { int flag, tmp; for (int i = 0; i \u0026lt; n - 1; i++) { flag = 0; for (int j = 0; j \u0026lt; n - i -1; j++) { if (arr[j] \u0026gt; arr[j + 1]) { tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 1; } } if (!flag) return; } } 筛选素数 暴力搜索\nbool isPrime(int n) { for (i = 2; i \u0026lt;= (int)sqrt(n); i++) {//如果n被i整除，则返回false if(n % i == 0) { return false; break; } } return true; // 反之则返回true } 6n±1法: 高效\nbool isPrime(int num) { if (num \u0026lt;= 3) { return num \u0026gt; 1; } // 不在6的倍数两侧的一定不是质数 if (num % 6 != 1 \u0026amp;\u0026amp; num % 6 != 5) { return false; } int sqrt = (int)sqrt(num); for (int i = 5; i \u0026lt;= sqrt; i += 6) { if (num % i == 0 || num % (i + 2) == 0) { return false; } } return true; } 逆序数 int fun(int num) { int S = 0; while (num \u0026gt; 0) { S =(S + num % 10)*10; num /= 10; } return S / 10; } 最大公约数 int gcd(int a, int b) { if (a % b == 0) return b; else return gcd(b, a % b); } 寻找共同祖先 int common(int x, int y) { if (x == y) return x; if (x \u0026gt; y) return common(x / 2, y); return common(x, y / 2); } 逆序输出 递归 void inverse(int n) { int num; scanf(\u0026#34;%d\u0026#34;, \u0026amp;num); if (n \u0026gt; 1) { inverse(n - 1); printf(\u0026#34;%d \u0026#34;, num); } if (n == 1) printf(\u0026#34;%d \u0026#34;, num); } 四舍五入指定小数 printf(\u0026#34;%.2f\u0026#34;, (int)(num * 100 + 0.5) / 100.0);//num为浮点数 其他进制转换二进制 int kTod(char s[], int k)//k进制数s { int d = 0; for (int i = 0; s[i] != \u0026#39;\\0\u0026#39;; i++) { d = d * k + (s[i] - \u0026#39;0\u0026#39;); } return d; } 数组循环移位 void ringShift(char* a, int n, int k) { int x = k % n; reverse(a, x); reverse(a + x, n - x); reverse(a, n); } void reverse(char* a, int n) { char tmp; for (int i = 0, k = n / 2; i \u0026lt; k; i++) { tmp = *(a + i); *(a + i) = *(a + n - 1 - i); *(a + n - 1 - i) = tmp; } } ","permalink":"http://note.leabol.top/posts/%E5%9F%BA%E7%A1%80%E7%AE%97%E6%B3%95%E5%BD%92%E7%BA%B3/","summary":"\u003ch1 id=\"基础算法归纳\"\u003e基础算法归纳\u003c/h1\u003e\n\u003cp\u003e#cs #c #算法\u003c/p\u003e\n\u003ch2 id=\"输出最大值\"\u003e输出最大值\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{ \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i[\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e], max;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003escanf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d %d %d\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003ei[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e], \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003ei[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e], \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003ei[\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e]);\u003cspan style=\"color:#75715e\"\u003e//通过数组来代替不同变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\tmax \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e i[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; j \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e n; j\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (max \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e i[j])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            max \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e i[j];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e, max);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"冒泡排序\"\u003e冒泡排序\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eBubbleSort\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e arr[], \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e n)\u003cspan style=\"color:#75715e\"\u003e//arr[] 在c中要用第一个数组值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e flag, tmp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; i \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; i\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tflag \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; j \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e n \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; j\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (arr[j] \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e arr[j \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\ttmp \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e arr[j];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tarr[j] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e arr[j \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tarr[j \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tmp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\tflag \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003eflag)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"筛选素数\"\u003e筛选素数\u003c/h2\u003e\n\u003cp\u003e暴力搜索\u003c/p\u003e","title":"基础算法归纳"},{"content":"#学习计划 #cs\n课程学习 编程入门 CS50 已完成 数据结构与算法 106X : 50-70小时 一些工具的使用与知识点 MIT-Missing-Semester: 10小时 组成原理 体系结构 操作系统( 106x前10集后) CMU CS15213: CSAPP: 难度很大,150小时 算法导论( 106x学完后) -mit 6.006 课外学习 工作岗位的了解，相关技术词汇的了解 积累项目经验, 对于本科生来说，积累项目实践经验的方式通常有三种，其一是加入到老师的课题组当中，这种方式更适合于重点大学的本科生，普通大学的本科生加入项目组的机会通常比较少；其二是参加一些专业比赛，通过参加专业比赛往往能够积累更多的实践经验，而且会获得专业老师的指导；其三是参加一些开源项目，这种方式对于学生的技术要求相对高一些，通常需要从阅读开源系统的源代码开始。 ","permalink":"http://note.leabol.top/posts/%E5%A4%A7%E4%B8%80%E7%9A%84cs%E5%AD%A6%E4%B9%A0%E8%AE%A1%E5%88%92/","summary":"\u003cp\u003e#学习计划 #cs\u003c/p\u003e\n\u003ch2 id=\"课程学习\"\u003e课程学习\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e编程入门\u003c/strong\u003e\nCS50  已完成\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数据结构与算法\u003c/strong\u003e\n106X : 50-70小时\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e一些工具的使用与知识点\u003c/strong\u003e\nMIT-Missing-Semester: 10小时\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e组成原理  体系结构 操作系统\u003c/strong\u003e( 106x前10集后)\nCMU CS15213: CSAPP: 难度很大,150小时\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e算法导论\u003c/strong\u003e( 106x学完后)\n-mit 6.006\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"课外学习\"\u003e课外学习\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e工作岗位的了解，相关技术词汇的了解\u003c/li\u003e\n\u003cli\u003e积累项目经验, 对于本科生来说，积累项目实践经验的方式通常有三种，其一是加入到老师的课题组当中，这种方式更适合于重点大学的本科生，普通大学的本科生加入项目组的机会通常比较少；其二是参加一些专业比赛，通过参加专业比赛往往能够积累更多的实践经验，而且会获得专业老师的指导；其三是参加一些开源项目，这种方式对于学生的技术要求相对高一些，通常需要从阅读开源系统的源代码开始。\u003c/li\u003e\n\u003c/ul\u003e","title":"学习计划"},{"content":"年计划 英语四级 考了 日语n1 没考 数据结构与算法 完成了30% 106X (26节课) 组成原理 体系结构 操作系统( 106x前10集后) 未开始 CMU CS15213: CSAPP 算法导论( 106x学完后) 未开始 -mit 6.006 (21节课) 网络 编译原理 ","permalink":"http://note.leabol.top/posts/%E5%AD%A6%E4%B9%A0%E8%AE%A1%E5%88%92/","summary":"\u003ch2 id=\"年计划\"\u003e年计划\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e英语四级  考了\u003c/li\u003e\n\u003cli\u003e日语n1  没考\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数据结构与算法\u003c/strong\u003e  完成了30%\n106X (26节课)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e组成原理  体系结构 操作系统\u003c/strong\u003e( 106x前10集后)  未开始\nCMU CS15213: CSAPP\u003c/li\u003e\n\u003cli\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e算法导论\u003c/strong\u003e( 106x学完后)  未开始\n-mit 6.006 (21节课)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e网络\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e编译原理\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"学习计划"},{"content":"#学习计划 #cs 大一上: 106X 106L 算法导论 大一下: CSAPP 网络 编译原理 大二上: 15-445 15-418 大二下: CS162 6.046 大三: 准备校招或者考研\n","permalink":"http://note.leabol.top/posts/%E8%AF%BE%E7%A8%8B%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/","summary":"\u003cp\u003e#学习计划  #cs\n大一上: 106X  106L  算法导论\n大一下: CSAPP  网络  编译原理\n大二上:  15-445  15-418\n大二下: CS162  6.046\n大三: 准备校招或者考研\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e","title":"学习计划"},{"content":"总结 计划的很理想，现实却有很多问题，过于相信课堂上的学习效率，上课时容易被老师打断，效率极低 高数与线代学习的不踏实，需要注意，英语有进步 注意平时积累，不要到最后抱佛脚 高数 微积分很重要, 是进入现代科学的基础. 但是对于cs来说重要性却没那么高, 所以重要性没那么强了. 鉴于这学期老师比较严格, 上课主要还是自学加写作业为主。ps：平时缺乏练习，导致花了很长时间复习。 线性代数 很重要的一门数学课, 在cs领域相当重要. 但是教科书与老师的教学都太落后, 所以选择用自己的教材自学, 上课也是写作业加自学为主 ps：自己选的教材翻译太烂，放弃了。之后老师上课声音太大，完全没法自学。最后通过网上的突击视频，花了三天考过了。 物理 虽然喜欢物理, 但是对于cs来说用处不大, 而且这门课内容多, 学习起来相当耗费时间. 而且老师也比较随和（ps：相当不行）, 所以主要通过作业来学习, 上课时间写之前的作业, 之后可以学习其他的东西PS：上课学习其他的东西，效率低，也没有写作业，老师基本不布置作业。 电子技术 偏硬件的课, 但是却浅尝辄止, 学一些皮毛, 要学习内容也是浩如烟海, 相当多. 所以也是通过作业来学习, 上课时间写之前的作业, 之后可以学习其他的东西 PS：上课学习其他的东西，效率低，也没有写作业，老师基本不布置作业。最后再老师划重点下，考过了。 英语 视听说, 老师不错, 上课可以听. 毕竟环境不适合学其他的 读写译, 老师不错, 比较认真, 上课只能听. 心理 水课 形式与政策 水课 ","permalink":"http://note.leabol.top/posts/%E5%A4%A7%E4%B8%80%E4%B8%8B%E5%AD%A6%E6%9C%9F%E8%AF%BE%E7%A8%8B%E8%80%83%E5%AF%9F%E5%AE%8C/","summary":"\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e计划的很理想，现实却有很多问题，过于相信课堂上的学习效率，上课时容易被老师打断，效率极低\u003c/li\u003e\n\u003cli\u003e高数与线代学习的不踏实，需要注意，英语有进步\u003c/li\u003e\n\u003cli\u003e注意平时积累，不要到最后抱佛脚\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"高数\"\u003e高数\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e微积分很重要, 是进入现代科学的基础. 但是对于cs来说重要性却没那么高, 所以重要性没那么强了. 鉴于这学期老师比较严格, 上课主要还是自学加写作业为主。\u003cstrong\u003eps：平时缺乏练习，导致花了很长时间复习。\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"线性代数\"\u003e线性代数\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e很重要的一门数学课, 在cs领域相当重要. 但是教科书与老师的教学都太落后, 所以选择用自己的教材自学, 上课也是写作业加自学为主 \u003cstrong\u003eps：自己选的教材翻译太烂，放弃了。之后老师上课声音太大，完全没法自学。最后通过网上的突击视频，花了三天考过了。\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"物理\"\u003e物理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e虽然喜欢物理, 但是对于cs来说用处不大, 而且这门课内容多, 学习起来相当耗费时间. 而且老师也比较随和（\u003cstrong\u003eps：相当不行）, 所以主要通过作业来学习, 上课时间写之前的作业, 之后可以学习其他的东西PS：上课学习其他的东西，效率低，也没有写作业，老师基本不布置作业。\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"电子技术\"\u003e电子技术\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e偏硬件的课, 但是却浅尝辄止, 学一些皮毛, 要学习内容也是浩如烟海, 相当多. 所以也是通过作业来学习, 上课时间写之前的作业, 之后可以学习其他的东西 \u003cstrong\u003ePS：上课学习其他的东西，效率低，也没有写作业，老师基本不布置作业。最后再老师划重点下，考过了。\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"英语\"\u003e英语\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e视听说, 老师不错, 上课可以听. 毕竟环境不适合学其他的\u003c/li\u003e\n\u003cli\u003e读写译, 老师不错, 比较认真, 上课只能听.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"心理\"\u003e心理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e水课\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"形式与政策\"\u003e形式与政策\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e水课\u003c/li\u003e\n\u003c/ul\u003e","title":"学习计划总结"},{"content":"文件控制函数 file control 功能描述 fcntl函数可以用来对已打开的文件描述符进行各种控制操作, 以改变已打开文件的的各种属性\n头文件\n#include \u0026lt;unistd.h\u0026gt; #include \u0026lt;fcntl.h\u0026gt; 函数原型 int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); c int fcntl(int fd, int cmd, struct flock *lock); 描述 fcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.\n针对cmd的值,fcntl能够接受第三个参数（arg）\nfcntl函数有5种功能c 复制一个现有的描述符（cmd=F_DUPFD）.\n获得／设置文件描述符标记(cmd=F_GETFD或F_SETFD).\n获得／设置文件状态标记(cmd=F_GETFL或F_SETFL).\n获得／设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).\n获得／设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).\ncmd 选项 F_DUPFD 返回一个如下描述的(文件)描述符:\n（1）最小的大于或等于arg的一个可用的描述符\n（2）与原始操作符一样的某对象的引用\n（3）如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)\n（4）相同的访问模式(读,写或读/写)\n（5）相同的文件状态标志(如:两个文件描述符共享相同的状态标志)\n（6）与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用\nF_GETFD 取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.\n如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg被忽略)\nF_SETFD 设置close-on-exec旗标。该旗标以参数arg的FD_CLOEXEC位决定。\nF_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略)\nF_SETFL 设置给arg描述符状态标志,可以更改的几个标志是：O_APPEND， O_NONBLOCK，O_SYNC和O_ASYNC。\nF_GETOWN 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略)\nF_SETOWN 设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明,否则,arg将被认为是进程id\n命令字(cmd)F_GETFL和F_SETFL的标志如下面的描述:\nO_NONBLOCK 非阻塞I/O ; 如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,read或write调用返回-1和EAGAIN错误 O_APPEND 强制每次写(write)操作都添加在文件大的末尾,相当于open(2)的O_APPEND标志\nO_DIRECT 最小化或去掉reading和writing的缓存影响.系统将企图避免缓存你的读或写的数据.\n如果不能够避免缓存,那么它将最小化已经被缓存了的数 据造成的影响.如果这个标志用的不够好,将大大的降低性能\nO_ASYNC 当I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候\n**注意：**在修改文件描述符标志或文件状态标志时必须谨慎，先要取得现在的标志值，然后按照希望修改它，最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令，这样会关闭以前设置的标志位。\n例子：\n//设置socket为非阻塞模式(套接字立即返回，不管I/O是否完成，该函数所在的线程会继续运行) fcntl(fd,F_SETFL,fcntl(fd,F_GETFD,0)|O_NONBLOCK); //F_SETFL 设置给arg描述符状态标志,可以更改的几个标志是：O_APPEND， O_NONBLOCK，O_SYNC和O_ASYNC。 //F_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略) //O_NONBLOCK 非阻塞I/O; fcntl的返回值 与命令有关。如果出错，所有命令都返回－1，如果成功则返回某个其他值。\n下列三个命令有特定返回值：\nF_DUPFD,F_GETFD,F_GETFL以及F_GETOWN。\n第一个返回新的文件描述符，第二个返回相应标志，最后一个返回一个正的进程ID或c负的进程组ID。\n一：第一种类似于dup操作，在这里不做举例。（fcnlt(oldfd, F_DUPFD, 0) \u0026lt;==\u0026gt;dup2(oldfd, newfd)） 二：设置close-on-exec旗标 在此函数中创建子进程，调用execl\n#include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;string.h\u0026gt; int main() { pid_t pid; //以追加的形式打开文件 int fd = fd = open(\u0026#34;test.txt\u0026#34;, O_TRUNC | O_RDWR | O_APPEND | O_CREAT, 0777); if(fd \u0026lt; 0) { perror(\u0026#34;open\u0026#34;); return -1; } printf(\u0026#34;fd = %d\\n\u0026#34;, fd); fcntl(fd, F_SETFD, 0);//关闭fd的close-on-exec标志 write(fd, \u0026#34;hello c program\\n\u0026#34;, strlen(\u0026#34;hello c program!\\n\u0026#34;)); pid = fork(); if(pid \u0026lt; 0) { perror(\u0026#34;fork\u0026#34;); return -1; } if(pid == 0) { printf(\u0026#34;fd = %d\\n\u0026#34;, fd); int ret = execl(\u0026#34;./main\u0026#34;, \u0026#34;./main\u0026#34;, (char *)\u0026amp;fd, NULL); if(ret \u0026lt; 0) { perror(\u0026#34;execl\u0026#34;); exit(-1); } exit(0); } wait(NULL); write(fd, \u0026#34;hello c++ program!\\n\u0026#34;, strlen(\u0026#34;hello c++ program!\\n\u0026#34;)); close(fd); return 0; } main测试函数c\nint main(int argc, char *argv[]) { int fd = (int)(*argv[1]);//描述符 printf(\u0026#34;fd = %d\\n\u0026#34;, fd); int ret = write(fd, \u0026#34;hello linux\\n\u0026#34;, strlen(\u0026#34;hello linux\\n\u0026#34;)); if(ret \u0026lt; 0) { perror(\u0026#34;write\u0026#34;);c return -1; } close(fd); return 0; } 执行后文件结果：\n[root@centOS5 class_2]# cat test.txt hello c program hello linuxc hello c++ program! 三：用命令F_GETFL和F_SETFL设置文件标志，比如阻塞与非阻塞 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;sys/types.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; #include \u0026lt;sys/stat.h\u0026gt; #include \u0026lt;fcntl.h\u0026gt; #include \u0026lt;string.h\u0026gt; /**********************使能非阻塞I/O******************** *int flags; *if(flags = fcntl(fd, F_GETFL, 0) \u0026lt; 0) *{ * perror(\u0026#34;fcntl\u0026#34;); * return -1; *} *flags |= O_NONBLOCK; *if(fcntl(fd, F_SETFL, flags) \u0026lt; 0) *{ * perror(\u0026#34;fcntl\u0026#34;); * return -1; *} *******************************************************/ /**********************关闭非阻塞I/O****************** flags \u0026amp;= ~O_NONBLOCK; if(fcntl(fd, F_SETFL, flags) \u0026lt; 0) { perror(\u0026#34;fcntl\u0026#34;); return -1; } *******************************************************/ int main() { char buf[10] = {0}; int ret; int flags; //使用非阻塞io if(flags = fcntl(STDIN_FILENO, F_GETFL, 0) \u0026lt; 0) { perror(\u0026#34;fcntl\u0026#34;); return -1; } flags |= O_NONBLOCK; if(fcntl(STDIN_FILENO, F_SETFL, flags) \u0026lt; 0) { perror(\u0026#34;fcntl\u0026#34;); return -1; } while(1) { sleep(2); ret = read(STDIN_FILENO, buf, 9); if(ret == 0) { perror(\u0026#34;read--no\u0026#34;); } else { printf(\u0026#34;read = %d\\n\u0026#34;, ret); } write(STDOUT_FILENO, buf, 10); memset(buf, 0, 10); } return 0;c } 四：设置异步IO 五：设置获取记录锁 结构体flock的指针：\nstruct flcok { short int l_type; /* 锁定的状态*/ //这三个参数用于分段对文件加锁，若对整个文件加锁，则：l_whence=SEEK_SET,l_start=0,l_len=0; short int l_whence;/*决定l_start位置*/ off_t l_start; /*锁定区域的开头位置*/ off_t l_len; /*锁定区域的大小*/ c pid_t l_pid; /*锁定动作的进程*/ }; _type 有三种状态:\nF_RDLCK 建立一个供读取用的锁定\nF_WRLCK 建立一个供写入用的锁定\n​ F_UNLCK 删除之前建立的锁定\nl_whence 也有三种方式:\nSEEK_SET 以文件开头为锁定的起始位置。\nSEEK_CUR 以目前文件读写位置为锁定的起始位置\nSEEK_END 以文件结尾为锁定的起始位置。\n#include \u0026#34;filelock.h\u0026#34; /* 设置一把读锁 */ int readLock(int fd, short start, short whence, short len) { struct flock lock; lock.l_type = F_RDLCK; lock.l_start = start; lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END lock.l_len = len; lock.l_pid = getpid(); // 阻塞方式加锁 if(fcntl(fd, F_SETLKW, \u0026amp;lock) == 0) return 1; return 0; } /* 设置一把读锁 , 不等待 */ int readLocknw(int fd, short start, short whence, short len) { struct flock lock; lock.l_type = F_RDLCK; lock.l_start = start; lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END lock.l_len = len; lock.l_pid = getpid(); // 非阻塞方式加锁 if(fcntl(fd, F_SETLK, \u0026amp;lock) == 0) return 1; return 0; } /* 设置一把写锁 */ int writeLock(int fd, short start, short whence, short len) { struct flock lock; lock.l_type = F_WRLCK; lock.l_start = start; lock.l_whence = whence; lock.l_len = len; lock.l_pid = getpid(); //阻塞方式加锁 if(fcntl(fd, F_SETLKW, \u0026amp;lock) == 0) return 1; return 0; } /* 设置一把写锁 */ int writeLocknw(int fd, short start, short whence, short len) { struct flock lock; lock.l_type = F_WRLCK; lock.l_start = start; lock.l_whence = whence; lock.l_len = len; lock.l_pid = getpid(); //非阻塞方式加锁 if(fcntl(fd, F_SETLK, \u0026amp;lock) == 0) return 1; return 0; } /* 解锁 */ int unlock(int fd, short start, short whence, short len) { struct flock lock; lock.l_type = F_UNLCK; lock.l_start = start; lock.l_whence = whence; lock.l_len = len; lock.l_pid = getpid(); if(fcntl(fd, F_SETLKW, \u0026amp;lock) == 0) return 1;c return 0; } ","permalink":"http://note.leabol.top/posts/linux-fcntl%E5%87%BD%E6%95%B0/","summary":"\u003ch1 id=\"文件控制函数--file-control\"\u003e文件控制函数  file control\u003c/h1\u003e\n\u003ch2 id=\"功能描述\"\u003e功能描述\u003c/h2\u003e\n\u003cp\u003efcntl函数可以用来对已打开的文件描述符进行各种控制操作, 以改变已打开文件的的各种属性\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e头文件\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;unistd.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;fcntl.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"函数原型\"\u003e\u003cstrong\u003e函数原型\u003c/strong\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efcntl\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e fd, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e cmd);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efcntl\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e fd, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e cmd, \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e arg);         \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ec\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efcntl\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e fd, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e cmd, \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e flock \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003elock);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"描述\"\u003e\u003cstrong\u003e描述\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003efcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.\u003c/p\u003e\n\u003cp\u003e针对cmd的值,fcntl能够接受第三个参数（arg）\u003c/p\u003e\n\u003ch3 id=\"fcntl函数有5种功能c\"\u003e\u003cstrong\u003efcntl函数有5种功能c\u003c/strong\u003e\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e复制一个现有的描述符（cmd=F_DUPFD）.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获得／设置文件描述符标记(cmd=F_GETFD或F_SETFD).\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获得／设置文件状态标记(cmd=F_GETFL或F_SETFL).\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获得／设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获得／设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"cmd-选项\"\u003e\u003cstrong\u003ecmd 选项\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eF_DUPFD\u003c/strong\u003e   返回一个如下描述的(文件)描述符:\u003c/p\u003e\n\u003cp\u003e（1）最小的大于或等于arg的一个可用的描述符\u003c/p\u003e\n\u003cp\u003e（2）与原始操作符一样的某对象的引用\u003c/p\u003e\n\u003cp\u003e（3）如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)\u003c/p\u003e\n\u003cp\u003e（4）相同的访问模式(读,写或读/写)\u003c/p\u003e\n\u003cp\u003e（5）相同的文件状态标志(如:两个文件描述符共享相同的状态标志)\u003c/p\u003e\n\u003cp\u003e（6）与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_GETFD\u003c/strong\u003e   取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.\u003c/p\u003e\n\u003cp\u003e如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg被忽略)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_SETFD\u003c/strong\u003e   设置close-on-exec旗标。该旗标以参数arg的FD_CLOEXEC位决定。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_GETFL\u003c/strong\u003e   取得fd的文件状态标志,如同下面的描述一样(arg被忽略)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_SETFL\u003c/strong\u003e   设置给arg描述符状态标志,可以更改的几个标志是：O_APPEND， O_NONBLOCK，O_SYNC和O_ASYNC。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_GETOWN\u003c/strong\u003e 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eF_SETOWN\u003c/strong\u003e 设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明,否则,arg将被认为是进程id\u003c/p\u003e\n\u003cp\u003e命令字(cmd)F_GETFL和F_SETFL的标志如下面的描述:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eO_NONBLOCK\u003c/strong\u003e    非阻塞I/O ; 如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,read或write调用返回-1和EAGAIN错误 　\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eO_APPEND\u003c/strong\u003e       强制每次写(write)操作都添加在文件大的末尾,相当于open(2)的O_APPEND标志\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eO_DIRECT\u003c/strong\u003e       最小化或去掉reading和writing的缓存影响.系统将企图避免缓存你的读或写的数据.\u003c/p\u003e\n\u003cp\u003e　　如果不能够避免缓存,那么它将最小化已经被缓存了的数 据造成的影响.如果这个标志用的不够好,将大大的降低性能\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eO_ASYNC\u003c/strong\u003e       当I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候\u003c/p\u003e\n\u003cp\u003e**注意：**在修改文件描述符标志或文件状态标志时必须谨慎，先要取得现在的标志值，然后按照希望修改它，最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令，这样会关闭以前设置的标志位。\u003c/p\u003e","title":"文件控制函数"},{"content":"杭州建人高复（杭师大) 2023**\n~~自作清高的大树，不但无法为人挡风遮雨，还可能给人带来灾难。~~树按照自己的本性生长，不需要顾及也无法顾及其他。大树只是自然地生长，枯萎，死亡。\n不公平是客观存在的，即使建立新的制度也依旧存在不公平。但只要不触及个人的底线或者根本利益，可以放平自己心态。如果损害他人来使自己获利，这是不能接受的。\n对手机已经是感情上的依赖了，所以一旦拿到手机，即使无事可做也会有安心感，尤其在安全区之外。这因该也是一种把内心寄托于外物的表现。寄情于物或者寄情于人都应当谨慎些。\n任何道理，不论多么了解，多么熟悉，都不如亲自尝试一遍，知与行的差距非常大，更何况还会遗忘。\n学习完全不会的东西与使用已经会的东西，做这些事所消耗的精力要远小于在意识模糊地带中寻找知识。因此减少在模糊地带的徘徊。2024年1月注 由此可见,，想要通过碎片化的知识来潜移默化的学习是效率底下的。沾花惹草式的学习，以后可能要花费更多的精力。\n学习需要大量的实践，当略有所思时，更应该不断的实践，而不是停下来苦思。因为很有可能是错的。\n自身精力的管理是一种非常重要的能力。即使是重复的日常生活，如果不去管理精力，也很难过得好。无意义的情绪波动，会让人心力憔悴，难以专心做事。因此专心只做一件事，放下多余的想法和各种执念，只做好自己。\n在眼前绽放的鲜活的生命力，令我震撼不已。我充满不可思议的崇拜的心情，注视着。那种生命力是如何形成的，我很好奇。我已经被这种生命力折服，看到这个场景，又给了我一些对这个世界的美好向往。\n正视自身，正视内心是一切进步的前提。只有正视了自己，才能了解自己的不足与极限，从而有所改变。正视自己的内心，才能明确自己想要的，从而有了目标。但是正视自己，并不是彻底的表达自我，正视自己可以说谎，可以违心，但这只是表象，自己不能被自己的谎话所蒙蔽，自己要明白自己。\n人生有两大目标，提高对世界的认知和提高自己的能力。两个相辅相成，若只有能力但认知浅显，最终只能成为一个好用的工具；而认知大于自身的能力是不可能， 认知来源于实践，而实践需要相应的能力那就只能无可奈何，徒增烦恼。提升认知可以通过读书，实践，思考来提高。而思考是最重要的一环，没有它，学的再多也是复述他人观点。\n大脑会下意识的逃避困难，寻求快乐。如何节约这个问题，是改变拖延症的关键。一个方法就是决定好目标后，就去做，不要想太多。\n","permalink":"http://note.leabol.top/posts/%E9%AB%98%E5%A4%8D%E6%97%B6%E6%9C%9F/","summary":"\u003cp\u003e\u003cem\u003e\u003cstrong\u003e\u003cstrong\u003e杭州建人高复（杭师大) 2023\u003c/strong\u003e\u003c/strong\u003e\u003c/em\u003e**\u003c/p\u003e\n\u003cp\u003e~~自作清高的大树，不但无法为人挡风遮雨，还可能给人带来灾难。~~树按照自己的本性生长，不需要顾及也无法顾及其他。大树只是自然地生长，枯萎，死亡。\u003c/p\u003e\n\u003cp\u003e不公平是客观存在的，即使建立新的制度也依旧存在不公平。但只要不触及个人的底线或者根本利益，可以放平自己心态。如果损害他人来使自己获利，这是不能接受的。\u003c/p\u003e\n\u003cp\u003e对手机已经是感情上的依赖了，所以一旦拿到手机，即使无事可做也会有安心感，尤其在安全区之外。这因该也是一种把内心寄托于外物的表现。寄情于物或者寄情于人都应当谨慎些。\u003c/p\u003e\n\u003cp\u003e任何道理，不论多么了解，多么熟悉，都不如亲自尝试一遍，知与行的差距非常大，更何况还会遗忘。\u003c/p\u003e\n\u003cp\u003e学习完全不会的东西与使用已经会的东西，做这些事所消耗的精力要远小于在意识模糊地带中寻找知识。因此减少在模糊地带的徘徊。\u003cem\u003e2024年1月注\u003c/em\u003e  由此可见,，想要通过碎片化的知识来潜移默化的学习是效率底下的。沾花惹草式的学习，以后可能要花费更多的精力。\u003c/p\u003e\n\u003cp\u003e学习需要大量的实践，当略有所思时，更应该不断的实践，而不是停下来苦思。因为很有可能是错的。\u003c/p\u003e\n\u003cp\u003e自身精力的管理是一种非常重要的能力。即使是重复的日常生活，如果不去管理精力，也很难过得好。无意义的情绪波动，会让人心力憔悴，难以专心做事。因此专心只做一件事，放下多余的想法和各种执念，只做好自己。\u003c/p\u003e\n\u003cp\u003e在眼前绽放的鲜活的生命力，令我震撼不已。我充满不可思议的崇拜的心情，注视着。那种生命力是如何形成的，我很好奇。我已经被这种生命力折服，看到这个场景，又给了我一些对这个世界的美好向往。\u003c/p\u003e\n\u003cp\u003e正视自身，正视内心是一切进步的前提。只有正视了自己，才能了解自己的不足与极限，从而有所改变。正视自己的内心，才能明确自己想要的，从而有了目标。但是正视自己，并不是彻底的表达自我，正视自己可以说谎，可以违心，但这只是表象，自己不能被自己的谎话所蒙蔽，自己要明白自己。\u003c/p\u003e\n\u003cp\u003e人生有两大目标，提高对世界的认知和提高自己的能力。两个相辅相成，若只有能力但认知浅显，最终只能成为一个好用的工具；而认知大于自身的能力是不可能， 认知来源于实践，而实践需要相应的能力\u003cdel\u003e那就只能无可奈何，徒增烦恼\u003c/del\u003e。提升认知可以通过读书，实践，思考来提高。而思考是最重要的一环，没有它，学的再多也是复述他人观点。\u003c/p\u003e\n\u003cp\u003e大脑会下意识的逃避困难，寻求快乐。如何节约这个问题，是改变拖延症的关键。一个方法就是决定好目标后，就去做，不要想太多。\u003c/p\u003e","title":"杭州建人高复（杭师大）"},{"content":"汲取知识并化为己用 自我规划的能力 搜索知识 归纳总结知识 利用好时间和工具资料 化为己用 形成系统,由薄读厚,由厚读薄 方式 讲给别人听 落实到具体的项目实现 有限时间内\n面对困难,压力,迷茫时,积极应对的勇气 这是正常现象,要接纳自己 不要与他人比较 兵来将挡水来土掩; 理解他人,包容他人,博爱之心 学会原谅自己,爱自己 人不是完美的,但这知识一个阶段,不代表一辈子 ","permalink":"http://note.leabol.top/posts/%E7%9F%A5%E9%9A%BE%E8%80%8C%E8%BF%9B-%E8%B4%B5%E5%9C%A8%E5%9D%9A%E6%8C%81-%E7%9C%81%E5%AF%9F%E4%BD%93%E6%82%9F-%E8%B4%B5%E4%BA%8E%E6%94%B9%E8%BF%87/","summary":"\u003ch2 id=\"汲取知识并化为己用\"\u003e汲取知识并化为己用\u003c/h2\u003e\n\u003ch4 id=\"自我规划的能力\"\u003e自我规划的能力\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e搜索知识\u003c/li\u003e\n\u003cli\u003e归纳总结知识\u003c/li\u003e\n\u003cli\u003e利用好时间和工具资料\u003c/li\u003e\n\u003cli\u003e化为己用\n\u003cul\u003e\n\u003cli\u003e形成系统,由薄读厚,由厚读薄\u003c/li\u003e\n\u003cli\u003e方式\n\u003cul\u003e\n\u003cli\u003e讲给别人听\u003c/li\u003e\n\u003cli\u003e落实到具体的项目实现\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有限时间内\u003c/p\u003e\n\u003ch2 id=\"面对困难压力迷茫时积极应对的勇气\"\u003e面对困难,压力,迷茫时,积极应对的勇气\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e这是正常现象,要接纳自己\u003c/li\u003e\n\u003cli\u003e不要与他人比较\u003c/li\u003e\n\u003cli\u003e兵来将挡水来土掩;\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"理解他人包容他人博爱之心\"\u003e理解他人,包容他人,博爱之心\u003c/h2\u003e\n\u003ch2 id=\"学会原谅自己爱自己\"\u003e学会原谅自己,爱自己\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e人不是完美的,但这知识一个阶段,不代表一辈子\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003c/h2\u003e","title":"汲取知识并化为己用"},{"content":"现代操作系统的内核（如 Linux 内核）中有一个专门的模块叫做：\n网络协议栈（Network Stack) 主要职责详解 职责 类比说明 技术术语 1. 接收和发送数据包 公司前台接收快递 \u0026amp; 发送包裹 数据链路层、IP 层、传输层 2. IP 地址管理 给每个员工分配邮箱地址 IPv4 / IPv6 地址配置 3. 路由选择 快递要走哪条路线最短最快 路由表（Routing Table） 4. 封装与解封装 包裹加标签 / 拆标签 数据封装（Encapsulation）与解封装（Decapsulation） 5. 传输控制（TCP） 控制文件是否完整送达 TCP 流量控制、拥塞控制 6. 端口号管理 不同部门接收不同类型的快递 端口绑定、监听、转发 7. 安全防护（防火墙） 保安检查包裹内容 Netfilter / iptables / nftables 8. NAT 转换 公司统一出口代理 Network Address Translation 9. 域名解析支持 内部电话簿查询联系方式 DNS 解析缓存、本地 hosts 10. 支持多种协议 公司支持各种沟通方式（电话、邮件、视频会议） 支持 TCP、UDP、ICMP、HTTP、HTTPS、FTP 等 类比图：操作系统网络部门的组织架构 小组 类比角色 职责 套接字接口组（Socket Layer） 客户接待员 接收进程请求（如浏览器访问网页） 传输组（TCP / UDP） 快递打包组 控制可靠传输或快速发送 网络组（IP 层） 邮政分拣中心 决定发往哪个城市（IP 地址） 链路组（MAC 层） 快递站 决定发给哪个局域网内的目标主机 路由组（Routing） 导航调度中心 选择最优路径（下一跳） 设备驱动组（NIC Driver） 快递员 实际把包裹送出去（通过网卡） 安全组（Netfilter / Firewall） 保安检查岗 检查是否允许通行 NAT 组 公司代理出口 统一管理内部员工对外通信 DNS 缓存组 内部电话簿管理员 记录域名与 IP 的对应关系 Linux 的网络部分是一个庞大的子系统，主要包括以下几个关键模块：\n应 使 如 T 分 I M 数 实 用 用 C 段 P A 据 际 程 s P 、 C 帧 通 序 s y 端 封 设 写 过 ： o s / 口 装 链 地 备 入 网 c c _ 号 、 路 址 驱 网 线 u k s 传 U 、 路 层 封 动 卡 / r e o 输 D 确 网 由 （ 装 缓 W l t 系 c 层 P 认 络 决 D 、 + 冲 i , - - 统 k - - （ 、 - - 层 策 - - a A - - 区 F - 用 A ↓ ↓ ↓ 调 e ↓ ↓ ↓ T 协 重 ↓ ↓ ↓ （ 、 ↓ ↓ ↓ t R ↓ ↓ ↓ 物 i ↓ 户 t P - - 用 t - - r 议 传 - - I T - - a P - - 理 - 空 e I - - 层 ( - - a 处 等 - - P T - - - - 层 发 - 间 l - - （ ) - - n 理 - - L - - L 查 - - （ 出 - n 发 - - S , - - s - - 层 、 - - i 询 - - N - e 送 - - o - - p - - ） 分 - - n 、 - - I - t 和 - - c s - - o - - 片 - - k 帧 - - C - , 接 - - k y - - r - - 重 - - 封 - - - 收 - - e s - - t - - 组 - - L 装 - - D - 浏 数 - - t _ - - - - - - a - - r - 览 据 - - s - - L - - - - y - - i - 器 - - L e - - a - - - - e - - v - - - a n - - y - - - - r - - e - - - y d - - e - - - - ） - - r - - - e t - - r - - - - - - ） - - - r o - - ） - - - - - - - - - ） ( - - - - - - - - - - - ) - - - - - - - - - - - - - - - - - - - - - - 等 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + ✅ 1. 套接字接口组（Socket Layer） 接收应用程序的请求（如 send(), recv()） 分配并管理端口号（如随机端口 54321） 支持多种协议（TCP、UDP、RAW socket） 将数据传递给传输层（TCP/UDP), 是用户空间与内核空间的桥梁 ✅ 2. 传输组（TCP / UDP） TCP：可靠传输、流量控制、拥塞控制 UDP：快速但不保证送达 ✅ 3. 网络组（IP 层） 处理 IP 地址、TTL（生存时间）\n分片重组（当包太大时）\n查找路由表\n使用 ARP 协议获取目标 MAC\n决定从哪个网卡发出去\n支持多路径负载均衡\n✅ 4. 链路组（MAC 层） 添加 MAC 地址头（源 MAC、目标 MAC） 将传输数据帧传给驱动 ✅ 6. 设备驱动组（NIC Driver） 控制网卡硬件（如 Intel E1000、Realtek RTL8111） DMA 机制：直接内存访问，提高效率 中断通知：数据已发完 / 已收到 ✅ 7. 安全组（Netfilter / Firewall） 匹配规则（iptables/nftables）\n修改、丢弃、转发数据包\n连接状态跟踪（conntrack）\n物 设 链 网 N 路 N 传 套 理 备 路 络 e 由 e 输 接 网 驱 层 层 t 决 t 层 字 络 动 （ （ f 策 f （ 接 （ 验 I i （ i T 口 接 证 P l 确 l C （ 收 t 定 t P 应 ↓ 数 ↓ M ↓ 层 ↓ e ↓ 目 ↓ e ↓ / ↓ 用 据 A ） r 标 r U 程 包 C 主 D 序 ） P 机 I P ） 地 R ） N ） 址 E P ） R U O T U （ T 防 I 火 N 墙 G ） （ D N A T ） ✅ 8. NAT 组（Network Address Translation） 修改源地址和端口 实现内网访问外网 支持端口复用（PAT） 相关工具的使用 socket api 1. lsof - 查看进程打开的网络连接 用途：列出进程打开的文件描述符（包括 Socket 连接）。\n常用命令：\n#查看网络连接 lsof -i\t# 查看所有网络连接 lsof -i -p \u0026lt;PID\u0026gt; # 按 PID 过滤 lsof -i -c nginx # 按进程名过滤（如 nginx） lsof -i :80 # 查看 80 端口的占用 lsof -i :8080-8090 # 查看 8080 到 8090 端口的连接 lsof -i TCP # 仅 TCP 连接 lsof -i UDP # 仅 UDP 连接 #查看打开文件 lsof -p \u0026lt;PID\u0026gt; # 查看进程打开的所有文件（含 Socket） lsof /var/log/nginx.log # 查看谁在访问某个文件 输出关键字段：\nCOMMAND：进程名称。 PID：进程 ID。 USER：运行进程的用户。 TYPE：类型（如 IPv4、IPv6）。 NODE：协议（如 TCP、UDP）。 NAME：连接地址（如 localhost:8080-\u0026gt;1.2.3.4:443）。 2. netstat 或 ss - 网络连接统计 用途：查看系统网络连接、路由表、接口统计等（ss 是更现代的替代工具）。\n常用命令：\n# 查看所有 TCP 连接及关联进程（需要 root 权限） netstat -tulnp # 查看某个进程的网络连接（按 PID） netstat -anp | grep \u0026lt;PID\u0026gt; ss -a # 显示所有连接（包括监听和非监听） ss -tunlp # 常用组合：显示所有 TCP/UDP 监听和连接 #按照状态过滤 ss -t state established # 查看所有已建立的 TCP 连接 ss -t state listening # 查看所有监听的 TCP 端口 ss -t state time-wait # 查看 TIME-WAIT 状态的连接 #按端口或ip过滤 ss -tunlp sport = :80 # 查看源端口为 80 的连接 !!! 等号左右空格不可少 ss -tunlp dport = :443 # 查看目标端口为 443 的连接 !!! 等号左右空格不可少 ss dst 192.168.1.100 # 目标 IP 为 192.168.1.100 的连接 ss src 10.0.0.1 # 源 IP 为 10.0.0.1 的连接 参数说明：\n-t：TCP 连接。 -u：UDP 连接。 -n：不解析域名（直接显示 IP）。 -l：仅监听中的连接。 -p：显示关联进程。 -4/-6：仅 IPv4 或 IPv6。 输出示例:\nN t u e c d t p p i d S E U t S N a T C t A O e B N N R 0 0 e c v - Q S 0 0 e n d - Q L 1 * o 9 : c 2 5 a . 3 l 1 5 6 3 A 8 d . d 1 r . e 1 s 0 s 0 : : P 5 o 4 r 3 t 2 1 P e e 3 r 9 * . : A 1 * d 5 d 6 r . e 6 s 6 s . : 1 P 8 o : r 8 t 0 👉 Rec-Q 和 Send-Q 表示当前队列中的数据大小 👉 Local Address:Port 是你的本地地址和端口 👉 Peer Address:Port 是目标地址和端口 👉 State 表示连接状态（ESTAB = 已连接）\n3. strace - 跟踪进程的 Socket 系统调用 用途：实时跟踪进程的 Socket 相关系统调用（如 socket, bind, connect, send, recv）。\n示例：\n# 跟踪进程的所有网络相关系统调用 strace -e trace=network -p \u0026lt;PID\u0026gt; # 跟踪特定系统调用（如 connect 和 send） strace -e trace=connect,sendto,recvfrom -p \u0026lt;PID\u0026gt; strace -f -e trace=network -p \u0026lt;PID\u0026gt; # 跟踪进程及其子进程的网络调用 strace -e trace=network -p \u0026lt;PID\u0026gt; -o network.log # 输出到文件 # 查看进程与某个 IP 的交互（结合 grep） strace -p \u0026lt;PID\u0026gt; -s 1024 -e trace=network 2\u0026gt;\u0026amp;1 | grep \u0026#34;1.2.3.4\u0026#34; 关键系统调用：\nsocket()：创建 Socket。\nbind()：绑定地址。\nconnect()：发起连接。\nsend()/recv()：发送/接收数据。\naccept()：接受连接。\n** 调试常见网络问题** 场景 1：连接被拒绝 若 connect 返回 ECONNREFUSED，表示目标端口未监听：\nconnect(3, {sa_family=AF_INET, ...}, 16) = -1 ECONNREFUSED (Connection refused) 场景 2：DNS 解析失败 若 getaddrinfo 失败，可能是域名解析问题：\nsocket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 sendto(3, \u0026#34;example.com\u0026#34;, ...) = 32 recvfrom(3, 0x7ffd..., 1024, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) 场景 3：数据传输异常 通过 sendto 和 recvfrom 的返回值，判断是否发送/接收了预期大小的数据：\nsendto(3, \u0026#34;payload\u0026#34;, 1024, 0, NULL, 0) = 512 # 实际发送 512 字节（可能被截断） recvfrom(3, buffer, 4096, 0, NULL, NULL) = -1 EAGAIN # 非阻塞模式下无数据可读 使用场景总结 快速定位端口占用： lsof -i :80 或 ss -tulnp | grep 80。 查看进程的实时网络调用： strace -e trace=network -p \u0026lt;PID\u0026gt; 。 传输层 同上ss 网络层 1. ip addr（IP 地址管理） 作用: 查看、添加或删除网络接口的 IP 地址（替代传统的 ifconfig）。\n常用命令\n命令 作用 ip addr show 查看所有接口的 IP 地址 ip addr add 192.168.1.100/24 dev eth0 给 eth0 添加 IP ip addr del 192.168.1.100/24 dev eth0 删除 eth0 的 IP 输出解析 2: eth0: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::211:22ff:fe33:4455/64 scope link valid_lft forever preferred_lft forever 1. 第一行：接口状态与基本属性 2: eth0：2 是内核分配的接口索引号。eth0 是接口名称（通常是以太网卡）。 \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt;： BROADCAST：支持广播通信。 MULTICAST：支持组播。 UP：接口已启用。 LOWER_UP：物理链路已连接（如网线插好）。 mtu 1500：最大传输单元（MTU）为 1500 字节（标准以太网值）。 qdisc fq_codel：使用的队列算法为 fq_codel（公平队列+流量控制）。 state UP：接口处于活动状态。 group default：接口属于默认组。 qlen 1000：传输队列长度为 1000 个数据包。 2. 第二行：MAC 地址 link/ether 00:11:22:33:44:55：接口的 MAC 地址（物理地址）。 brd ff:ff:ff:ff:ff:ff：广播 MAC 地址（所有位为 FF 表示广播帧）。 3. 第三行：IPv4 地址配置 inet 192.168.1.100/24： IPv4 地址为 192.168.1.100。 子网掩码为 /24（即 255.255.255.0）。 brd 192.168.1.255：广播地址 scope global：地址作用域为全局（可跨子网通信）。 eth0：地址绑定的接口名称。 附加行：IPv4 地址有效期 valid_lft forever：地址永久有效（无过期时间）。 preferred_lft forever：地址永久优先（无临时降级）。 2. ip route（路由管理） 作用: 管理 路由表（决定数据包如何转发）。\n常用命令\n命令 作用 ip route show 查看当前路由表 ip route add 10.0.0.0/24 via 192.168.1.1 dev eth0 添加静态路由 ip route add default via 192.168.1.1 设置默认网关 ip route del 10.0.0.0/24 删除路由 输出解析 default via 192.168.1.1 dev eth0 proto static metric 100 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 10.0.0.0/24 via 192.168.1.1 dev eth0 default via 192.168.1.1：默认网关（所有非本地流量走 192.168.1.1）。 192.168.1.0/24 dev eth0：本地子网，直接通过 eth0 通信。 10.0.0.0/24 via 192.168.1.1：静态路由，访问 10.0.0.0/24 的流量走 192.168.1.1。 dev eth0: 数据包出口的网络接口（网卡） proto static: 路由来源：static（手动配置）、kernel（内核自动生成）、dhcp 等 metric 100: 路由优先级（值越小优先级越高） scope link: 局域网通信 4. ip neigh（ARP 缓存管理） 作用: 查看和管理 ARP 缓存表（IP 和 MAC 地址的映射）。\n常用命令\nip neigh show\t#查看 ARP 表 输出解析\n192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE 192.168.1.100 dev eth0 lladdr aa:bb:cc:dd:ee:ff STALE lladdr 00:11:22:33:44:55**：对应的 MAC 地址。 REACHABLE：ARP 条目有效（STALE 表示可能过期）。 5. traceroute（路由追踪） 作用: 显示 数据包从本机到目标主机的路径（经过哪些路由器）。\n常用命令 : traceroute \u0026lt;ip\u0026gt;\n输出解析\ntraceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.1.1 (192.168.1.1) 1.234 ms 1.123 ms 1.456 ms 2 10.0.0.1 (10.0.0.1) 5.678 ms 6.789 ms 7.123 ms 3 203.0.113.1 (203.0.113.1) 10.111 ms 11.222 ms 12.333 ms 4 8.8.8.8 (8.8.8.8) 15.444 ms 16.555 ms 17.666 ms 30 hops max：最多追踪 30 跳（防止无限循环）。 ","permalink":"http://note.leabol.top/posts/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E6%A0%88network-stack/","summary":"\u003cp\u003e现代操作系统的内核（如 Linux 内核）中有一个专门的模块叫做：\u003c/p\u003e\n\u003ch1 id=\"网络协议栈network-stack\"\u003e网络协议栈（Network Stack)\u003c/h1\u003e\n\u003ch2 id=\"主要职责详解\"\u003e主要职责详解\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e职责\u003c/th\u003e\n          \u003cth style=\"text-align: left\"\u003e类比说明\u003c/th\u003e\n          \u003cth\u003e技术术语\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e1. 接收和发送数据包\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e公司前台接收快递 \u0026amp; 发送包裹\u003c/td\u003e\n          \u003ctd\u003e数据链路层、IP 层、传输层\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e2. IP 地址管理\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e给每个员工分配邮箱地址\u003c/td\u003e\n          \u003ctd\u003eIPv4 / IPv6 地址配置\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e3. 路由选择\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e快递要走哪条路线最短最快\u003c/td\u003e\n          \u003ctd\u003e路由表（Routing Table）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e4. 封装与解封装\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e包裹加标签 / 拆标签\u003c/td\u003e\n          \u003ctd\u003e数据封装（Encapsulation）与解封装（Decapsulation）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e5. 传输控制（TCP）\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e控制文件是否完整送达\u003c/td\u003e\n          \u003ctd\u003eTCP 流量控制、拥塞控制\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e6. 端口号管理\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e不同部门接收不同类型的快递\u003c/td\u003e\n          \u003ctd\u003e端口绑定、监听、转发\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e7. 安全防护（防火墙）\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e保安检查包裹内容\u003c/td\u003e\n          \u003ctd\u003eNetfilter / iptables / nftables\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e8. NAT 转换\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e公司统一出口代理\u003c/td\u003e\n          \u003ctd\u003eNetwork Address Translation\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e9. 域名解析支持\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e内部电话簿查询联系方式\u003c/td\u003e\n          \u003ctd\u003eDNS 解析缓存、本地 hosts\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e10. 支持多种协议\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e公司支持各种沟通方式（电话、邮件、视频会议）\u003c/td\u003e\n          \u003ctd\u003e支持 TCP、UDP、ICMP、HTTP、HTTPS、FTP 等\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"类比图操作系统网络部门的组织架构\"\u003e类比图：操作系统网络部门的组织架构\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e小组\u003c/th\u003e\n          \u003cth\u003e类比角色\u003c/th\u003e\n          \u003cth\u003e职责\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e套接字接口组（Socket Layer）\u003c/td\u003e\n          \u003ctd\u003e客户接待员\u003c/td\u003e\n          \u003ctd\u003e接收进程请求（如浏览器访问网页）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e传输组（TCP / UDP）\u003c/td\u003e\n          \u003ctd\u003e快递打包组\u003c/td\u003e\n          \u003ctd\u003e控制可靠传输或快速发送\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e网络组（IP 层）\u003c/td\u003e\n          \u003ctd\u003e邮政分拣中心\u003c/td\u003e\n          \u003ctd\u003e决定发往哪个城市（IP 地址）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e链路组（MAC 层）\u003c/td\u003e\n          \u003ctd\u003e快递站\u003c/td\u003e\n          \u003ctd\u003e决定发给哪个局域网内的目标主机\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e路由组（Routing）\u003c/td\u003e\n          \u003ctd\u003e导航调度中心\u003c/td\u003e\n          \u003ctd\u003e选择最优路径（下一跳）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e设备驱动组（NIC Driver）\u003c/td\u003e\n          \u003ctd\u003e快递员\u003c/td\u003e\n          \u003ctd\u003e实际把包裹送出去（通过网卡）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e安全组（Netfilter / Firewall）\u003c/td\u003e\n          \u003ctd\u003e保安检查岗\u003c/td\u003e\n          \u003ctd\u003e检查是否允许通行\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNAT 组\u003c/td\u003e\n          \u003ctd\u003e公司代理出口\u003c/td\u003e\n          \u003ctd\u003e统一管理内部员工对外通信\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDNS 缓存组\u003c/td\u003e\n          \u003ctd\u003e内部电话簿管理员\u003c/td\u003e\n          \u003ctd\u003e记录域名与 IP 的对应关系\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eLinux 的网络部分是一个庞大的子系统，主要包括以下几个关键模块：\u003c/p\u003e","title":"网络协议栈（Network）"},{"content":"集合 集合一般被定义为：由一个或多个确定的元素所构成的整体。 集合有什么特性呢？\n首先，集合里的元素类型不一定相同。 你可以将商品看作一个集合，也可以将整个商店看作一个集合，这个商店中有人或者其他物品也没有关系。\n其次，集合里的元素没有顺序。 我们不会这样讲：我想要集合中的第三个元素，因为集合是没有顺序的。\n事实上，这样的集合并不直接存在于编程语言中。然而，实际编程语言中的很多数据结构，就是在集合的基础上添加了一些规则形成的。\n列表 列表（又称线性列表）的定义为：是一种数据项构成的有限序列，即按照一定的线性顺序，排列而成的数据项的集合。\n列表的概念是在集合的特征上形成的，它具有顺序，且长度是可变的。你可以把它看作一张购物清单：\n购物清单中的条目代表的类型可能不同，但是按照一定顺序进行了排列； 购物清单的长度是可变的，你可以向购物清单中增加、删除条目。 在编程语言中，列表最常见的表现形式有数组和链表，而我们熟悉的栈和队列则是两种特殊类型的列表。除此之外，向列表中添加、删除元素的具体实现方式会根据编程语言的不同而有所区分。\n数组 数组是列表的实现方式之一，也是面试中经常涉及到的数据结构。\n正如前面提到的，数组是列表的实现方式，它具有列表的特征，同时也具有自己的一些特征。然而，在具体的编程语言中，数组这个数据结构的实现方式具有一定差别。比如 C++ 和 Java 中，数组中的元素类型必须保持一致，而 Python 中则可以不同。Python 中的数组叫做 list，具有更多的高级功能。\n那么如何从宏观上区分列表和数组呢？这里有一个重要的概念：索引。\n首先，数组会用一些名为 索引 的数字来标识每项数据在数组中的位置，且在大多数编程语言中，索引是从 0 算起的。我们可以根据数组中的索引，快速访问数组中的元素。\n而列表中没有索引，这是数组与列表最大的不同点。\n其次，数组中的元素在内存中是连续存储的，且每个元素占用相同大小的内存。\n相反，列表中的元素在内存中可能彼此相邻，也可能不相邻。比如列表的另一种实现方式——链表，它的元素在内存中则不一定是连续的。\n","permalink":"http://note.leabol.top/posts/%E9%9B%86%E5%90%88%E5%88%97%E8%A1%A8%E5%92%8C%E6%95%B0%E7%BB%84/","summary":"\u003ch3 id=\"集合\"\u003e\u003cem\u003e集合\u003c/em\u003e\u003c/h3\u003e\n\u003chr\u003e\n\u003cp\u003e\u003ca href=\"https://baike.baidu.com/item/%E9%9B%86%E5%90%88/2908117?fr=aladdin\"\u003e集合\u003c/a\u003e一般被定义为：由一个或多个确定的元素所构成的整体。\n集合有什么特性呢？\u003c/p\u003e\n\u003cp\u003e首先，\u003cstrong\u003e集合里的元素类型不一定相同\u003c/strong\u003e。 你可以将商品看作一个集合，也可以将整个商店看作一个集合，这个商店中有人或者其他物品也没有关系。\u003c/p\u003e\n\u003cp\u003e其次，\u003cstrong\u003e集合里的元素没有顺序\u003c/strong\u003e。 我们不会这样讲：我想要集合中的第三个元素，因为集合是没有顺序的。\u003c/p\u003e\n\u003cp\u003e事实上，这样的集合并不直接存在于编程语言中。然而，实际编程语言中的很多数据结构，就是在集合的基础上添加了一些规则形成的。\u003c/p\u003e\n\u003ch3 id=\"列表\"\u003e\u003cem\u003e列表\u003c/em\u003e\u003c/h3\u003e\n\u003chr\u003e\n\u003cp\u003e列表（又称线性列表）的定义为：是一种数据项构成的有限序列，即按照一定的线性顺序，排列而成的数据项的集合。\u003c/p\u003e\n\u003cp\u003e列表的概念是在集合的特征上形成的，它具有顺序，且长度是可变的。你可以把它看作一张购物清单：\u003c/p\u003e\n\u003cp\u003e购物清单中的条目代表的类型可能不同，但是按照一定顺序进行了排列；\n购物清单的长度是可变的，你可以向购物清单中增加、删除条目。\n在编程语言中，列表最常见的表现形式有数组和链表，而我们熟悉的栈和队列则是两种特殊类型的列表。除此之外，向列表中添加、删除元素的具体实现方式会根据编程语言的不同而有所区分。\u003c/p\u003e\n\u003ch4 id=\"数组\"\u003e数组\u003c/h4\u003e\n\u003chr\u003e\n\u003cp\u003e数组是列表的实现方式之一，也是面试中经常涉及到的数据结构。\u003c/p\u003e\n\u003cp\u003e正如前面提到的，数组是列表的实现方式，它具有列表的特征，同时也具有自己的一些特征。然而，在具体的编程语言中，数组这个数据结构的实现方式具有一定差别。比如 C++ 和 Java 中，数组中的元素类型必须保持一致，而 Python 中则可以不同。Python 中的数组叫做 list，具有更多的高级功能。\u003c/p\u003e\n\u003cp\u003e那么如何从宏观上区分列表和数组呢？这里有一个重要的概念：\u003cem\u003e索引\u003c/em\u003e。\u003c/p\u003e\n\u003cp\u003e首先，数组会用一些名为 索引 的数字来标识每项数据在数组中的位置，且在大多数编程语言中，索引是从 0 算起的。我们可以根据数组中的索引，快速访问数组中的元素。\u003c/p\u003e\n\u003cp\u003e而列表中没有索引，这是数组与列表最大的不同点。\u003c/p\u003e\n\u003cp\u003e其次，数组中的元素在内存中是连续存储的，且每个元素占用相同大小的内存。\u003c/p\u003e\n\u003cp\u003e相反，列表中的元素在内存中可能彼此相邻，也可能不相邻。比如列表的另一种实现方式——链表，它的元素在内存中则不一定是连续的。\u003c/p\u003e","title":"集合 列表 数组"},{"content":" char类型与int一样,也可以存储数字,不过只能存一个字节,多于一个字节的数,只取最右边的; 用\u0026rsquo; \u0026lsquo;括起来的数字,相当于ascll中的字符, 值大小等于ascll值. 例如 \u0026lsquo;5\u0026rsquo; == (int) 53 。 当要将整型数字赋值给char字符串时， 要用 str[i] =number + \u0026#39;0\u0026#39;; 或者用\nsprintf(str*, \u0026#34;%d\u0026#34;, number); //sprintf 函数 数组初始化{0}时，并不是全赋值为零，而是\u0026rsquo;\\0\u0026rsquo;，而但他是ascll的第0位，所以%d输入时为0；但用%c时不会输出 char * p = \u0026#34;abc\u0026#34;;//abc是常量,p指向\u0026#34;abc\u0026#34;,不能更改 char arr[] = \u0026#34;abc\u0026#34;;//将abc赋值到arr所指的地方,而arr是变量,可以更改 ","permalink":"http://note.leabol.top/posts/%E7%BC%96%E7%A8%8B%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/","summary":"\u003cul\u003e\n\u003cli\u003echar类型与int一样,也可以存储数字,不过只能存一个字节,多于一个字节的数,只取最右边的; 用\u0026rsquo; \u0026lsquo;括起来的数字,相当于ascll中的字符, 值大小等于ascll值.  例如 \u0026lsquo;5\u0026rsquo; == (int) 53 。   当要将整型数字赋值给char字符串时， 要用\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003estr[i] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003enumber \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e或者用\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003esprintf\u003c/span\u003e(str\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e, number); \u003cspan style=\"color:#75715e\"\u003e//sprintf 函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e数组初始化{0}时，并不是全赋值为零，而是\u0026rsquo;\\0\u0026rsquo;，而但他是ascll的第0位，所以%d输入时为0；但用%c时不会输出\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e p \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e;\u003cspan style=\"color:#75715e\"\u003e//abc是常量,p指向\u0026#34;abc\u0026#34;,不能更改\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e arr[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e;\u003cspan style=\"color:#75715e\"\u003e//将abc赋值到arr所指的地方,而arr是变量,可以更改\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"编程的一些问题"}]