操作系统开发问题
这段时间没事在自己写操作系统,其中遇到了很多问题,想和大家分享一下我研究的一点成果
以及讨论一下技术方案。
在我理解的操作系统,主要由 Bootloader + Kernel + Shell 所组成,目的是完成一个管理
计算机资源并提供相关接口开发应用程序的平台基础。
Bootloader:可以分为 Boot 程序和 Loader 两个程序所组成,也可以直接是一个程序完成,
但主要看 Kernel 架构和文件系统等选型决定是分两个程序还是一个程序完成工作。
其实 Bootloader 主要是计算机启动时自动加载到内存执行的第一个程序,也被称为引导程序,
它是运行在 CPU 的实时模式下的 16 位程序,而系统启动时只会加载 512 个字节,即一个扇区
的数据到内存执行,这也就限制了 Boot 程序或这说 Bootloader 程序编译后的大小不能超过
512 个字节,如果文件系统定义得不那么复杂,而且内核加载过程不需要特别初始化的话,这个程序
完全可以用 Bootloader 的方式一次加载内核(比如内核程序直接有汇编开发)。
但如果想实现 C/C++ 语言来开发内核,而编译器又是现有系统的编译器,这个 Bootloader 就得
分两个步骤来完成,先是 Boot 程序,功能是先加载 Loader 程序,然后由 Loader 程序初始化
好环境再加载 Kernel。
Kernel:这个所谓的内核,在我的理解就是提供了一堆预先写好的基础函数放到内存中共其他应用
程序调用。比如提供 OS_ReadFile、OS_LoadAPI 等函数,然后应用程序启动时可以通过特定的内存
地址找到这些函数的内核地址,从而用跳转指令调用这些函数。这些一系列的函数累加起来,实现
了系统所谓的内存管理、进程管理、线程管理、设备管理等等功能。然后 Kernel 的初始化及载入
过程完成后就可以把执行权移交给 Shell 与用户进行交互了。
Shell:在我的理解,Shell 就是人机交互的管理程序,如 DOS 下的命令行形式的人机交互方式,
或者是 Windows 下图形模式的人机交互方式,理论上说,这个 Shell 是系统执行的第一个“应用程序”,
理论上 Shell 里的过程基本上全是调用 Kernel 所提供的函数完成的。
到现在为止,对于写“操作系统”,我越来月不清晰,因为有以下几个顾虑。
1、开发环境
如编译器是自己写好还是用现成的好,如果用现成的,免不了要根据别的系统走开发路线,而且
也未必是能实现我想用 BASIC 开发系统的想法。但自己写编译器难度又较大。
2、内核的定制
如果用高级语言开发内核,还是与编译器有关,包括应用程序的执行问题,这个内核还是与编译器
息息相关,如果不考虑高级语言,用汇编来写,灵活性比较大,但如果要写大,代码管理也很叫人
头痛。而且最终的应用程序管理部分也会卡在可执行程序的格式定义上,因为将来的应用程序不可能
也全由汇编开发,这样就没什么价值了。
3、是否采用现有系统的模型
比如 Windows、Linux、MacOS、DOS、uCos、Menuet OS 等,都有自己的特点,自己定制方式是比较随意,
但相对来说所有东西都要自己做,就比如如果不用现有的文件系统格式,自己弄一个,可能会更方面,
但即使格式化和复制文件这种操作才最初的时候都要自己写一个程序去做这种事,然后才能调试效果。
但如果运用的现有系统架构,那今后的开发路线就是个模仿的过程,基本上还不如直接用那些系统来得
有意义。
目前在开发操作系统的时候,我采用了软盘上用的 FAT12 文件系统进行系统设计,主要是为了在 Windows
下方便管理文件。但发现这样很耗代码,因为 FAT12 文件系统大致分为4个部分:
1、BOOT 区域,就是引导用的第一个扇区,也就是所谓的 MRB 表。如果要保持标准的 FAT12 文件系统,
必须按照它的固有格式开发 Boot 程序,如:开始是3个字节的跳转指令,然后跟着 BPB 表信息,然后
才开始 Boot 程序的代码,最后就是 0xAA55 的引导结束符号,所以,这个 BOOT 程序实际上最多只有
448 个字节。
2、FAT 表区,这个 FAT 其实是 File Allocation Table 的缩写,主要是记录文件数据的族链信息,
只有在文件数据内容大于一个族(512字节)才会具体指向数据的逻辑族地址,如果文件数据内
容在512个字节内,是不会指向具体的数据所在逻辑扇区地址的。而且系统通常会备份一个FAT表,
这样即使有一个 FAT 表因为磁盘坏道不能正常读取文件数据起始地址,也有另外一个表可以顶上。
3、FDT 表区,这个 FDT 其实是 File Directory Table 的缩写,主要存放文件名、目录名或卷标等
信息,包括名称、属性、相关日期时间,数据起始扇区号、文件大小等,当文件大小小于或等于
512个字节时,其实没必要访问 FAT 表去读文件数据,因为 FDT 表已经有了数据起始扇区号的信息,
因为只有一个扇区数据,直接读那个扇区就好了。当文件数据超出一个扇区时,就需要依赖 FAT
表进行数据族链的查找了,只要在 FAT 表中搜索一个链头与 FDT 数据起始扇区号相同的就可以
按照循序访问到文件数据分布在那几个扇区号上。
4、数据区,也就是存储文件具体数据的地方,通常文件数据会以扇区为单位存储。如果文件较大,
可能产生一个文件存放数据分布在不连续的扇区上,如一个5个扇区数据的文件,他可能存储在
0x003 0x004 0x005 0x01E 0x01F 的地方,这时候就需要 FAT 的族链来找到这些数据的分布扇区
情况。
看到这里,可以想象,如果要根据这种方式找到指定文件,并把所有数据读出来需要的代码量肯定不小。
而且同时还要将运行模式初始化到 32 位系统的保护模式,并执行现型系统的可执行文件格式,那就更难
了。所以我采用 Boot 和 Loader 分开的模式,先加载稍微大点的 Loader 程序,然后再用 Loader 程序
处理这些更复杂的操作并加载内核。
但我这段时间还看了一些别的 OS 代码,发现, Kernel 部分如果不用现有系统编译器的程序编写,如果
直接用汇编写,整个初始化过程可以更简单,那个 Loader 程序其实就可以直接写成 Kernel 了。
我的想法是用 Basic 开发这个系统,本来的方案是这样,先写一个 BASIC 编译器,主要思路是写一堆
的汇编函数,模拟 Basic 的语法函数过程,然后分析 Basic 语法,把配合的语法用汇编替代,这样实现
Basic to Asm 的功能,然后再用汇编编译器编译程序。
这样即使使用的是 Basic 语言,其实出来的还是汇编的效果。不过因为全是调用封装的汇编函数,效率
肯定与直接用汇编根据情况编写代码要低一点。但起码实现了 Basic 开发系统的可能性。
但后来在运用 NASM 编译器时,发现 NASM 缺少些指令,如 cmps 等等,MASM 就没这种问题,但也存在
别的问题,所以我的代码该按照 NASM 的标准翻译还是 MASM 的标准翻译又成为了一个问题。后来就自己
去看了下 CPU 指令集相关的资料,发现历年来系统的发展、各种 CPU 指令系统的升级累加,从这方面入
手也不容易,比如 Inter 的 x86、Pentium 、MMX、CISC指令集等等等等,除了多还要考虑程序的兼容性
等等。感觉自己按照 CPU 指令集编写 basic 编译器写操作系统的想法越来越远。
相对来说,觉得用汇编写内核和应用程序要比用这种高级语言简单得多,但如果这样做下去,这个系统也
没什么价值。所以想大家给点方案,怎么去设计这个系统比较好。
如:用什么编译器?结构如何?文件系统有没有更好的方案?……
[最优解释]
虽然不知道楼主在说什么,但是感觉楼主很厉害的样子
[其他解释]
可惜unix之父死了,不然你还可以向他讨教讨教。
[其他解释]
2、用 Linux 的 GCC 编译器
这种方式就是解读 ELF 文件格式,将 PE 代码加载到内存,然后进行跳转,但担心今后系统
可能好跟着 Linux 走,比如 GNU 什么的概念都要按 Linux 慢慢加进去。
3、用 Windows 的编译器
这种方式与 Linux 类似,就是解读 Windows 下的 PE 文件,然后跳转执行,和用 GCC 的
担心一样,今后的路线需要向 Windows 靠拢,不然编译出来的很多程序同样执行不了,最起
码没有相关的 NTAPI 和 API 函数,也不可能直接复制微软的来用,一个侵权,二个这样做
也没意义,三个就是 Windows 的程序关联性很强,真要这么做工程量比 Linux 的 GCC 要
大很多,而且不是开源,有问题也很难找,起码 Linux 还是个开源的东西,不懂还可以看他
的代码去理解(虽然也很多)。
还有就是 Kernel 与编译器基本上是挂钩的,比如 Basic 编译器在编译 Print 语句时,作为
应用程序的开发,肯定不是直接操作 BIOS 中断或走保护模式控制显存的方式来处理这种问题,
应该是调用 Kernel 的某个接口函数来执行这个过程,至于是在控制台模式输出还是在图形界面
的窗口里输出,应该有系统内核根据应用程序模式及配置决定,而编译器编译的代码只是调用 Kernel
接口而已。但如果先开发 Kernel,意味着 Kernel 程序就不是用高级语言,如果先开发编译器,
就意味着必须先策划好 Kernel 才好设计编译器。所以最终纠结还是编译器问题,我计划这样,
先用文档方式定义出 Kernel 的应用程序接口,然后先在 Windows 下写个编译器,当编译器写
好了,再用这个编译器开发 Kernel,即使其中有问题,慢慢修改编译器到符合开发系统与系统应用
程序的地步,这样感觉可能会好点。
[其他解释]
楼主可以参考下unix的内核代码。这些你可以在国外的网站上下载到,也可以去一些大型的图书馆里找到权威的文献。
另外操作系统发展至今已经是个相当复杂的概念,单凭一个人就算是做到支持输入输出已经是个很庞大的工程了。我建议还是借用下现成的一些代码跟基础库,在他们的基础上再进行开发。这样做更加有效率。
不过有些话我还是说下。《程序员的自我修养》一书的作者俞甲子说过,他曾经花了很多功夫去编写一个操作系统,从内核到API接口到底层硬件驱动什么的都钻研过,做到后来发现除了满足下好奇心没有任何可供商业化的方向,最终放弃了。
在现今社会,知识只有转化为经济效益才能获得肯定。我希望楼主的努力最终通过商业利益获得肯定。
[其他解释]
该回复于2011-11-21 10:29:52被版主删除
[其他解释]
佩服LZ的钻研能力~~
[其他解释]
充分利用bios,无论操作系统如何变化,bios包含的功能都是一样的
[其他解释]
太厉害了,虽然看不懂,还是得顶一下。
[其他解释]
全是以汇编作为开发方案,虽然说可以支持 BASIC,但那个 BASIC 其实就是个文本文件,执行起
来就像 ASP 一样,属于 BASIC 脚本程序。看到 MikeOS 就感觉特别担心自己做成这样。
[其他解释]
好像看到过同事桌上的有本书叫做什么一步一步学编写操作系统
[其他解释]
#include <noahs.bi>
#include "lib\nscomm32.cls"
#include "SKForm.cls"
#include "Form1.bas"
Dim MenuName,ClassName As String
Dim Form1 As SKForm
Dim IsExit As Boolean
Public Function WinMain(ByVal hInstance As Long, & _' 实例句柄
ByVal hPrevInstance As Long, & _'
ByRef lpCmdLine() As String, & _' 命令参数,字符串数组形式,以空格或Tab符分割
ByVal nCmdShow As Long) As Long' 命令参数数组可用的最大下标
IsExit = False
Set Form1 = New SKForm
Form1.OnInitialize = AddressOf Form1_Initialize
Form1.OnLoad = AddressOf Form1_Load
Form1.OnUnload = AddressOf Form1_Unload
Form1.Show
Dim msg As MSG
Do
GetMessage msg, NULL, 0, 0
TranslateMessage msg
DispatchMessage msg
Loop While IsExit = False
WinMain = 0
End Function
#If Not defined(SK_CLASS_LIB_SKFORM_CLASS)
Public Class SKForm
Public Event OnShow()
Public Event OnLoad()
Public Event OnCommand()
Private mvarhWnd As Long'局部复制
Private Sub Class_Initialize()
End Sub
Private Sub Class_Terminate()
End Sub
Public Sub Show()
RaiseEvent OnShow()
End Sub
Friend Property Let hWnd(ByVal vData As Long)
mvarhWnd = vData
End Property
Friend Property Get hWnd() As Long
hWnd = mvarhWnd
End Property
Public Operator Get = () As Long
End Operator
Public Operator Set = (ByRef FunAddress As Long)
End Operator
End Class
Public Class MyForm:SKForm
Private Event OnCommand()
End Class
#End If
Private Sub Form1_Initialize()
End Sub
Private Sub Form1_Load()
End Sub
Private Sub Form1_Unload(Cancel As Integer)
End Sub
#If Not defined(NOAH_SYSTEM_CLASS_LIB_NSCOMM32_CLASS)
#include "NSComm32.bas"
#Pragma Comment("NSComm32.lib")
Public Class NSComm
'==================== Class Property ( 类属性 ) ====================
' 端口属性
Public Declare Property Get Port() As Integer
Public Declare Property Let Port(ByVal iData As Integer)
' 波特率属性
Public Declare Property Get BaudRate() As Long
Public Declare Property Let BaudRate(ByVal lngData As Long)
' 数据比特位大小属性
Public Declare Property Get BitSize() As Byte
Public Declare Property Let BitSize(ByVal byData As Byte)
' 奇偶校检属性
Public Declare Property Get Parity() As Byte
Public Declare Property Let Parity(ByVal byData As Byte)
' 停止位属性
Public Declare Property Get StopBits() As Byte
Public Declare Property Let StopBits(ByVal byData As Byte)
'==================== Class Process ( 类方法 ) ====================
'---------- Not return's process( 无返回过程 ) ----------
' 打开关闭着的串口
Public Declare Sub Open()
' 关闭已打开的串口
Public Declare Sub Close()
'---------- Have return's process( 有返回过程 ) ----------
' 发送数据到串口
Public Declare Function Send(lpBuffers() As Byte) As Long
'==================== Class Event ( 类事件 ) ====================
' 当收到串口数据时产生该事件
Public Declare Event OnRead(lpReadData() As Byte,ByVal dwCount As Long)
End Class
#End If
#If Not defined(NOAH_SYSTEM_CLASS_LIB_NSCOMM32_MODULE)
Public Const NOPARITY= 0
Public Const ODDPARITY= 1
Public Const EVENPARITY= 2
Public Const MARKPARITY= 3
Public Const SPACEPARITY= 4
Public Const ONESTOPBIT= 0
Public Const ONE5STOPBITS= 1
Public Const TWOSTOPBITS= 2
Public Const CBR_110= 110
Public Const CBR_300= 300
Public Const CBR_600= 600
Public Const CBR_1200= 1200
Public Const CBR_2400= 2400
Public Const CBR_4800= 4800
Public Const CBR_9600= 9600
Public Const CBR_14400= 14400
Public Const CBR_19200= 19200
Public Const CBR_38400= 38400
Public Const CBR_56000= 56000
Public Const CBR_57600= 57600
Public Const CBR_115200= 115200
Public Const CBR_128000= 128000
Public Const CBR_256000= 256000
#End If
rem ==================== 注释用法1 ====================
rem 这是传统的 BASIC 语言注释的用法
rem 在每行 rem 语句后的所有文字内容都被视为注释内容
' ==================== 注释用法2 ====================
' 这是 Microsoft Visual Basic 常用的注释用法
' 与 rem 语句类似,只不过用的是单引号作为注释符
'* ==================== 注释用法3 ====================
这是 Noah Basic++ 特有的注释的用法
类似 C++ 语言的注释用法,由起始注释符和结束注释符
所组成,支持多行注释和穿插注释。特别在函数说明中
特别有用,不过这种代码注释不能穿插到字符串内。
*'
#include "time.cls"' Noah Basic++ 新增加的概念,引入某个对象或 bpp 文件,有点像 asp 的引用文件感觉
Dim Form1 As Form
Public Sub Main()
Msgbox "hello world!",64,"第一个程序"
Set Form1 = new Form
Form1.Caption = "第一个窗口"
Form1.OnLoad = AddressOf Form1_Load' 对象事件可以这样用了
Form1.Show
End Sub
Public Sub Form1_Load()
Dim objTempAs Object
'* ========================================
加载一个按钮
======================================== *'
Set objTemp = Form1.Controls.Add("CommandBox"'* 按钮对象名称 *', & _
"Command1"'* 自定义对象名称 *')
objTemp.Move 500,10,100,30
objTemp.Caption = "演示"' 按钮标签
objTemp.OnClick = AddressOf Connamd1_Click' 按钮事件
objTemp.Visible = True
Set objTemp = Form1.Controls.Add("PictureBox","Picture1")
End Sub
Public Sub Connamd1_Click()
Dim BasicVarAs Long
Dim byTemp()As Byte
Dim fsAs Integer
BasicVar = 512
Redim byTemp(BasicVar-1)
'* ============================================================
读取软驱的 0 磁头 0 磁道 第 1 个扇区的数据并保存到文件中
============================================================ *'
' 演示在 Noah Basic++ 中使用汇编语言的用法
#asm' 这里是表示以下开始汇编语言代码编写的标识符
; 这里是 Noah Basic++ 新增加的概念,使用汇编语言
; 在分号后所有文字内容都被视为注释内容
;------------------------
; 通过调用 BIOS 中断 13h 实现读取软盘数据
;------------------------
pushbx; 将 es:bx 放入栈
movah, 02h; 通过功能 02H 设置为读扇区功能
moval, 1; 设置要读的扇区数
movch, 0; 设置要读的磁道(柱面)号
movcl, 1; 设置要读的起始扇号
movdh, 0; 设置要读的磁头(面)号
movdl, 0; 设置要处理的驱动器号( 00H-7FH 表示软驱 00h是第一个软驱,01h是第二个软驱..., 80H-0FFH 表示硬盘 )
movbx, $&byTemp; 设置缓冲区的地址==========(这里比较特殊,用 $ 符号引用 Basic 中的变量)==========
int13h; 调用 BIOS 中断开始处理
popbx; 将 es:bx 移出栈
#endasm' 这里是表示结束以上汇编语言代码编写的标识符
' 将读到的数据保存到 c:\fdboo.bin 文件里
fs = FreeFile
Open "c:\fdboo.bin" For Binary As #fs
Put #fs, 1, byTemp
Close #fs
'* ============================================================
演示执行 C++ 代码
============================================================ *'
' 演示在 Noah Basic++ 中使用 C++ 语言的用法
#cpp
inti;// 定义一个带符号的整形变量 i
BYTE*byTemp;/* 定义一个无符号单字节的指针变量 */
byTemp = (BYTE *)malloc(10*sizrof(BYTE));// 为指针分配 10 个字节的内存空间
for(i=0;i<10;i++){
byTemp[i] = (BYTE)(i+(BYTE)$BasicVar);// 这里比较特殊,用 $ 符号引用 Basic 中的变量
}
free(byTemp);// 释放 byTemp 指针的内存空间
#endcpp
'* ============================================================
演示调用 API 函数
============================================================ *'
End Sub
越来越少,给人的感觉玩 VB 的就没几个高手。其实偷懒和走捷径是人都会这么想,这也无可厚非,除非
那个人看得特别透或完全没头脑,不然不可能没有这种想法,但是因为起初就是因为底子不好和偷懒走捷
才选的 VB,也很容易被别的因素影响不继续走这条路。所以 VB 程序员真正能玩上6-7年的人并不多,
甚至有 5 年都已经不多了。
其实我一直认为:“是人玩程序,不是程序玩人”的这种理念是正确的,Basic 其实能够很好的做到这点,
但微软为了让 Basic 更强大,把他改得更加复杂(指vb.net),既然都到了这种地步(复杂程度),还不如
直接去玩 c/c++ 呢,所以 vb.net 至今我都不怎么用。我宁可去玩 C/C++、汇编、Delphi 我都不去弄它。
但说句实话,vb6 的确有很多缺点,因为这些缺点,导致我多年来很多项目做得都不是很满意,如果要做
专业的程序,特别是有关网络、图形、硬件操作和有关执行效率的程序,我都不会选择 VB,因为这些东西
用 VB 做起来虽然思路可以很清晰、开发速度可以很快,但执行的起来确实有很多让人不能接受的地方。
就目前来说,做项目或是自己写程序,我都很少用 VB 了,为自己写点小工具还可以,说道商业化的东西,
基本上都不考虑 VB,除非很简单的项目并且觉得 VB 能满足需求的可能会考虑一下。但我又不想就这么放弃
这种开发理念,只有自己把 VC 当 VB 来玩,所以自己写了很多类,然后把过程写得像 VB 一样,还模拟
了很多 VB 的概念在 VC 里用。其实也有想过专门写一个类似 VB 的 Basic 编译器在 Windows 下使用,
但想到曾经的一些自动化项目工程中,用 Windows 的情况,就觉得太没意思了,那时候都想不用 PC 来
弄了,都想直接上 ARM 来弥补 Windows 的这种不稳定情况。但 ARM 上的 Windows 其实也好不到哪去,
而且很多东西缺失,虽然同样是 VC 开发,但用起来的确麻烦一点。后来看了 ARM 上的 Linux、Android
还有 u/Cos 等相关资料和源码,也做过不少实验,发现操作系统如果做起来其实也不是想象的那么复杂,
就决定尝试研究这一块,不过一开始不是搞 ARM ,而是直接搞 x86 的系统,因为不用整天去接硬件调试,
x86完全可以用虚拟机实现测试,很方便,所以后来看了很多书籍和相关资料还有源代码,也就开始干了
现在我在干的事情。
记得以前的帖子中讨论过一个话题,是说 XP 系统是 Basic 开发的,当时说到MS肯定有自己开发系统
的 BASIC 编译器,就好比 QB 这种编译器,肯定还有没公布的 Basic 编译器内部使用,但没得到确认。
我就在想,如果我真的弄个 Basic 编译器来开发个系统,这样即使不会汇编、不会 C/C++ 的业余人事都
有可能开始研究这一块技术,相信这样一来搞 Basic 的人群也不至于对系统这种东西完全没有概念,即使
我的系统没什么商业价值,但起码会对很多 Basic 程序员有一定程度的影响,不至于 basic 的开发
理念没人为此努力的就此没落下去,这也算是个好事。当然,至于这系统要与目前的系统一较长短是
比较难的,但如果用到自动化项目上也不是不可能,毕竟很多自动化项目其实要求不高,主要还是稳定性
和成本,如果这个系统要求的硬件环境不高,支持x86、x64、ARM,开发简单快速,并且稳定可靠,相信
还是会有一定市场价值的,但这就要看市场运作怎么去做了,不是单纯比较技术或完善技术就能成功的。
记得上面 14# 的兄弟说过,那个写《程序员的自我修养》的作者遇到过你说的这种问题,因为市场和
资金问题最后放弃了。其实在我看来那只是众多失败者的案例之一,在“成功学”里,很多人都是靠着
过人的毅力和努力,有时候还要靠点运气才有可能成功的。如果没有毅力,根本就没有机会等到“有运气”
的那天,上天怎么可能这么轻易就让你成功呢?我从不相信这种好事会在我身上轻易发生。所以对于
这种结果的期待我并不大,我相信只要坚持,我肯定会有所得,至于得到的是金钱、名誉或只是个人
一生的无憾,就要看各人的实际情况和运气了,这种东西的得失,只是各人根据各人的价值观去评判
的问题,我只要知道我可以接受就好了,没必要去纠结这种问题。
[其他解释]
版主们都泡哪去了,还不快加精
[其他解释]
俺现在觉得unix系统的思想还是可以借鉴的。楼主直接用C做系统吧,应用程序用Basic嘛。
其实,我是来等楼主成功的。
[其他解释]
成功总是在执着中,呵呵
[其他解释]
你说的"写 photoshop 的兄弟"应该是指laviewpbt吧,HOHO.
我也曾有过和你一样的疑问,问他到底为了什么,又不能赚钱.
后来我明白了,其实这种心情就是一种执着,也是一种发泄,并没有什么"为什么要做这个","为什么要这么做"之类的问题.
支持楼主.也许这个操作系统不能给你带来收入,但一定会带来大量经验,甚至有可能在这个过程中领悟到新的东西.
很多时候都不是为了钱,大家能在这里碰见就证明了这一点,嘿嘿.
不过我在技术上是帮不了你的,原因大家都知道,哇哈哈哈哈哈哈....
衷心为你加油!!
[其他解释]
“执着”这词包含着不理性而坚持的意思,我觉得我做这件事情并没有什么不理性的地
方,而且觉得这么做很理性。
比如每一个学习编程的人都会有这么个体验,刚开始学编程的时候没什么技术水平,根
本没办法用学到的那么点技能创造利益,因为自己技术水平还不够,甚至连一份程序员
的工作都找不到。但过了一两年后,自己的技术稍微成熟点后,开始有了一份程序员的
工作或接到第一份程序开发的单子,这时候前面几年所学的技术才开始创造出所谓的利
益,也才会感觉到有价值。当工作久了,自己的技术水平得到不断的提高,这种时候就
可以很容易的运用自己曾经累积的经验和技术很快的创造出物质上的利益。
可能有人认为,既然已经有了应用程序的开发基础,而且能够直接创造利益了,为什么
还要选择做这种似乎没边的事情呢?难道这不就是“执着”吗?
回头看看这个过程,难道说前面几年做的这些事情是不理智的?是“执着”?不可能这
么说吧。同样的角度,当你不了解程序开发的时候,同样会认为搞一个复杂的程序是多
么神奇,会搞人工资能、3D游戏是多么的神奇,多么的高不可攀,不知道要学到哪一年
才可能赚钱,而且也不知道你现在看见的那些牛人同样与你经过多年后又会到何种技术
境界,会觉得根本没法比。但真正入了这个行业后发现,人工智能也没那么牛,3D游戏
也不难搞,只要有精力和资金支持,想去弄肯定会弄出来,根本不像原来想象的那么高
不可攀,也没有那么神奇的感觉。
其实操作系统的开发也是这样,因为不了解,所以觉得不可能,但了解了之后,也不会
觉得有多神奇,其实只是个工作量较大的体力活,只是可能会烦恼有没有资金和兴趣玩
下去而已。但如果这不会影响到自身经济来源,又能不在乎做这件事情的成败得失,我
觉得没什么好很烦恼的,过程只会是很开心的进行。
我是这么想的,即使不靠它赚钱也没什么。就好像去KTV玩,一次花一两千去这么玩也
只是为了开心而已,我玩的这个不但不需要花钱,还可能赚钱,有什么不好,对我来说
得到的快感绝对比去KTV来得多,最主要是我觉得是在玩,是在享受,是我生活中的娱
乐插曲,享受的项目点而已,我根本不在乎它的成败,根本就不在乎其中的得失,完全
以一种享受过程的心态去面对,这怎么能理解为“执着”呢?
我相信那位用写 photoshop 的兄弟也一样,因为他根本不是程序员,只是某大学的一
个讲师,具体什么科目忘记了,但几年前与他在 Q 上聊过,他也是出于爱好而且不计
得失的在做这件事情,每当有了成果还来 CSDN 与大家分享,因为他喜欢 VB ,所以
就用他喜欢的开发工具开发他喜欢的东西来玩这没什么呀,如果他是为了开发这个 VB
版的 Photoshop,影响到生活,最终目的还是是为了赚钱,这样可以认为他是“执着”,
但他都不在乎得失,有没因为这东西影响自己的生活,何来“执着”之说。
这种行为只能是说他能“坚持”下来了,而不是“执着”的做着。
[其他解释]