<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>程序员的自我修养 on </title>
    <link>https://note.lican.site/tags/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E8%87%AA%E6%88%91%E4%BF%AE%E5%85%BB/</link>
    <description>Recent content in 程序员的自我修养 on </description>
    <generator>Hugo</generator>
    <language>en</language>
    <copyright>© lican.asia All rights reserved</copyright>
    <lastBuildDate>Wed, 28 Oct 2020 20:52:52 +0800</lastBuildDate>
    <atom:link href="https://note.lican.site/tags/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E8%87%AA%E6%88%91%E4%BF%AE%E5%85%BB/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>应用编译，计算机中那些一定要掌握的知识细节</title>
      <link>https://note.lican.site/posts/posts/reading/programmer-compile-link/</link>
      <pubDate>Wed, 28 Oct 2020 20:52:52 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/programmer-compile-link/</guid>
      <description>&lt;p&gt;”Hello World“ 程序几乎是每个程序员入门和开发环境测试的基本标准。代码如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#inclue &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int main()&#xA;{&#xA;&#x9;printf(&amp;#34;Hello Wolrd\n&amp;#34;);&#xA;&#x9;return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;编译该程序，再运行，就基本完成了所有新手的第一个程序。表面看起来轻轻松松，毫无悬念。但是实际上单纯这几下操作，就已经包含了不少暗操作。本着追根溯源的目的，我们将进一步对其流程进行分析。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a8040c0fc18257d2891d4b570b02c44d.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其内部主要包含 4 个步骤，分别是：预处理、编译、汇编以及链接。由于篇幅问题本文主要涉及前三部分，链接部分将会放到下一篇文章来讲解。&lt;/p&gt;&#xA;&lt;h2 id=&#34;预编译&#34;&gt;预编译&lt;/h2&gt;&#xA;&lt;p&gt;程序编译的第一步是 “预编译” 环境。主要作用是处理源代码文件中以 ”#“ 开始的预编译指令，例如：&lt;code&gt;#include&lt;/code&gt;、&lt;code&gt;#define&lt;/code&gt; 等。&lt;/p&gt;&#xA;&lt;p&gt;常见的处理规则是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;将所有 &lt;code&gt;#define&lt;/code&gt; 删除，并且展开所有的宏定义。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;处理所有条件预编译指令，比如 &lt;code&gt;if&lt;/code&gt;、&lt;code&gt;ifdef&lt;/code&gt;、&lt;code&gt;elif&lt;/code&gt;、&lt;code&gt;else&lt;/code&gt;、&lt;code&gt;endif&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;处理 &lt;code&gt;#include&lt;/code&gt; 预编译指令，将所包含的文件插入到该预编译指令的位置（可递归处理子级引入）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;删除所有的注释。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;添加行号和文件名标识，以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时显示行号。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;保留所有的 &lt;code&gt;#pragma&lt;/code&gt; 编译器指令，后续编译器将会使用。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在预编译后，文件中将不包含宏定义或引入。因为在预编译后将会全部展开，相应的代码段均已被插入文件中。像 Go 语言中的话，主要是 &lt;code&gt;go generate&lt;/code&gt; 命令会涉及到相关的预编译处理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;编译&#34;&gt;编译&lt;/h2&gt;&#xA;&lt;p&gt;第二步正式进入到 &amp;ldquo;编译&amp;rdquo; 环境。主要作用是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。该部分通常是整个程序构建的核心部分，也是最复杂的部分之一。&lt;/p&gt;&#xA;&lt;p&gt;执行编译操作的工具，一般称其为 “编译器”。编译器是将高级语言翻译成机器语言的一个工具。例如我们平时用 Go 语言写的程序，编译器就可以将其编译成机器可以执行的指令及数据。那么我们就不需要再去关心相关的底层细节，因为使用机器指令或汇编语言编写程序是一件十分费时及乏味的事情。&lt;/p&gt;&#xA;&lt;p&gt;且高级语言能够使得程序员更关注程序逻辑的本身，不再需要过多的关注计算机本身的限制，具有更高的平台可移植性，能够在多种计算机架构下运行。&lt;/p&gt;&#xA;&lt;h3 id=&#34;编译过程&#34;&gt;编译过程&lt;/h3&gt;&#xA;&lt;p&gt;编译过程一般分为 6 步：扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。整个过程如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/c1e4902df20b68df654229d9618b9d58.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们结合上图的源代码（Source Code）到最终目标代码（Final Target Code）的过程，以一段最简单的 Go 语言程序的代理例子来复现和讲述整个过程，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main&#xA;&#xA;import (&#xA;&#x9;&amp;#34;fmt&amp;#34;&#xA;)&#xA;&#xA;func main() {&#xA;&#x9;fmt.Println(&amp;#34;Hello World.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;词法分析&#34;&gt;词法分析&lt;/h3&gt;&#xA;&lt;p&gt;首先 Go 程序会被输入到扫描器中，可以理解为所有解析程序的第一步，都是读取源代码。而扫描器的任务很简单，就是利用有限状态机对源代码的字符序列进行分割，最终变成一系列的记号（Token）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>必知必会！计算机里一些基本又重要的概念</title>
      <link>https://note.lican.site/posts/posts/reading/programmer-accom-base/</link>
      <pubDate>Sat, 17 Oct 2020 00:25:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/programmer-accom-base/</guid>
      <description>&lt;p&gt;最近在翻阅文章时，看到全成推荐的《程序员的自我修养》，这是一本讲链接、装载与库的计算机图书，看了下目录后觉得挺有意思。&lt;/p&gt;&#xA;&lt;p&gt;因此决定每读一章就将其读书笔记整理记录下来，分享给大家。&lt;/p&gt;&#xA;&lt;p&gt;目录：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/bf202dccad8c3f8efb3726854b72e850.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;不要让-cpu-打盹&#34;&gt;不要让 CPU 打盹&lt;/h2&gt;&#xA;&lt;p&gt;在计算机发展早期，CPU 资源十分昂贵。如果一个 CPU 只能运行一个程序，那么当程序在读写磁盘（进行 I/O 操作）时，CPU 就空闲下来了。这在当时简直就是巨大的浪费。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/df419c04c95fc7d58cc6f6f34a2fb7fd.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;CPU 只能和一个程序A “聊天“，其他来再多的程序BCD，都没有任何操作的空间。就像早年的手机，打电话和上网（语音/数据）只能二选一，作为 CPU 的你，并不能多线程操作。&lt;/p&gt;&#xA;&lt;p&gt;因此机智的人们很快就编写了一些监控程序，希望来解决这个问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;多道程序multiprogramming&#34;&gt;多道程序（Multiprogramming）&lt;/h3&gt;&#xA;&lt;p&gt;多道程序起，操作系统正式具有同时运行多个程序的能力。&lt;/p&gt;&#xA;&lt;p&gt;其是让 CPU 一次读取多个程序放入内存中。当某个程序暂时无须使用 CPU 时，监控程序就把另外的正在等待 CPU 资源的程序启动，以此使得 CPU 能够充分地利用起来。这种策略的确大大的提高了 CPU 资源的利用率。&lt;/p&gt;&#xA;&lt;h4 id=&#34;真实场景&#34;&gt;真实场景&lt;/h4&gt;&#xA;&lt;p&gt;你在 Windows 上点击鼠标 10 分钟以后系统才有反应，那是多么无奈的事情。因为没有优先级区分，自然一路排下来也就不知道要等到什么时候了，相当于半饿死。&lt;/p&gt;&#xA;&lt;h4 id=&#34;存在的问题&#34;&gt;存在的问题&lt;/h4&gt;&#xA;&lt;p&gt;核心问题在于程序之间的调度策略太粗糙。对于多道程序来删，程序之间部分轻重缓急，也就是说不存在优先级的区分。因此如果有些程序急需使用 CPU 来完成一些任务，那么很有可能会很长时间后才有机会被分配到 CPU，才得以继续往下运行。&lt;/p&gt;&#xA;&lt;h3 id=&#34;分时系统time-sharing-system&#34;&gt;分时系统（Time-Sharing System）&lt;/h3&gt;&#xA;&lt;p&gt;程序运行模式改为协作的模式，在原有的多道程序继续升级改造，即每个程序运行一段时间以后都主动让出 CPU 给其他程序，使得一段时间内每个程序都有机会运行一小段。&lt;/p&gt;&#xA;&lt;h4 id=&#34;真实场景-1&#34;&gt;真实场景&lt;/h4&gt;&#xA;&lt;p&gt;比如你点击一下鼠标或按下一个键盘按键后，他会相较前者能够更快的得到响应，因为他好歹是存在切换的可能性。&lt;/p&gt;&#xA;&lt;h4 id=&#34;存在问题&#34;&gt;存在问题&lt;/h4&gt;&#xA;&lt;p&gt;这时候的监控程序已经比原有多道程序的模式已经复杂了不少，完整的操作系统雏形已经基本形成，很早期的 Windows（Windows 95 和 Windows NT 之前），MacOS X 之前的 MacOS 版本都是采用这种分时系统的方式来进行程序调度。&lt;/p&gt;&#xA;&lt;p&gt;其仍然存在问题，核心在于若一个程序一直在进行一个耗时计算，便会一直霸占着 CPU 不放，那么操作系统也没有不放，就会导致其他程序都只能无限等待，相当于就是系统假死了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;多任务系统multi-tasking&#34;&gt;多任务系统（Multi-tasking）&lt;/h3&gt;&#xA;&lt;h4 id=&#34;背景&#34;&gt;背景&lt;/h4&gt;&#xA;&lt;p&gt;在分时系统中，一个程序死循环就会导致系统假死，并且其运行效率并不高，只能解决当时的交互式环境。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
