Toggle navigation
科创
{{ getSearchSuggestionLabel(suggestion) }}
{{ part.text }}
查看更多
登录
 
注册
电波
论坛
专栏
应用
登录
注册
{{ getSearchSuggestionLabel(suggestion) }}
{{ part.text }}
查看更多
论坛
>
计算机科学
>
软件综合
文号
t23984
阅读
6871
回复
4
收藏
5
【版主推荐】程序设计语言
我说要有光
2010/03/17
软件综合
IP:北京
各位转载请注明出处。
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
阅读指引
读懂此文,需要
以下
基础
1.
至少
写过
1
000
行的代码。
2.
汇编基础
(静态数据段,代码段,堆栈段)
有以下
或者类似
知识就更好了
1.
C
语言编译
,
C++
对象模型,
MFC
反射的实现。
2.
JAVA
的动态编译器原理,
3.
使用过
javascript
,
Python
,
PHP
:
经历过
其代码和
类型
在
运行时
的
自由性
4.
计算机
组成原理
序
——
一些问题
1.
程序设计语言的目的
是什么?
2.
为什么大多数语言有控制流?逐行执行
+
跳转。
这与我们的需求差很远(例如
一个教务管理系统。)
3.
为什么类型申明
在
C
语言中
要与控制流隔离开来
?
4.
现在主流语言最基本的元素是?
5.
有没有语言它的类型结构,在运行时也可以改变?
动态性?
什么是动态性?
1.
编译后确定了什么信息
,
之后
不再
改变
。
2.
运行时可以改变、添加什么。
3.
运行时是否保存着类型信息。
程序中的
信息分为几类?
1.
数据信息
a)
编译时
Meta-Data
元数据
(类型框架
,空间占用
)
b)
运行时
Meta-Data
元数据(继承体系
,
用于
new
或者反射
)
(
特别区别编译与运行的
Meta-Data
的不同。
许多时候
就是这里弄昏
头
了。
)
c)
堆栈段
中地址偏移
(
C++
的
switch case
中
不能声明变量
;
共享内存
)
d)
静态段中地址
2.
指令信息
a)
加载代码段(
需要操作系统
或者虚拟机
支持
,
例如动态链接库,动态类加载,
lisp
语言自生成代码)
语言举例
汇编语言
汇编语言没有动态性吗?
没有
。
首先
,
寄存器
、
数据段、
堆栈
、
代码段
完全由程序员
控制
。
完完全全是写死了的。
然后
,
根据冯诺伊曼
机
的规则;
取指令,执行,取指令,执行
……
既然都有数据段了,还要堆栈段来做什么?
这不是多余
?
一开始
本
没有堆栈,
直到
60
年代
出现了
module
模块
化
,才有了堆栈
。
汇编中的模块叫子程序,
不过仍旧靠程序员全权
控制
。
堆栈
和模块化
的优点有?
1.
递归
2.
功能
分离到模块
,可复用
3.
封装
作用域
堆栈和
模块化
的缺点有?
1.
时间上:
保存
现场、还原
现场
的代价
(
另,高级语言
编译
“
消除尾递归
”
节约部分
成本)
2.
空间上:
爆栈
的危险
C
语言
C
语言比起汇编多了什么东西?
1.
编译器
2.
表达式
3.
函数与模块
{}
(
真
·
模块
化
)
4.
类型(
原子类型
、
结构类型
、
数组
、
指针
)
5.
头文件,库
总之,
C
语言并没有比汇编多了新的特性,它只是把汇编的繁琐操作
抽象
出来
,让编译器完成
,减轻程序员负担
。
编译器的作用是?(减少程序员负担)
1.
解析表达式
,控制流
(汇编中指令总是
1-3
个操作数
,而表达式可以多个操作数
)
2.
模块和函数的抽象
(
完成
堆栈中保存恢复现场的工作)
3.
类型变量的管理
a)
编译时
的
Meta-Data
(
需要记住各个
struct
的
成员
,记住
数组的长度
;编译结束即丢弃。
)
b)
计算出每个变量相对于该模块的偏移(
一旦算出该偏移,将固定在执行码中,无法改变
;就是说编译完成后,所有变量的偏移地址都固定下来
了
。
c)
对变量的存储进行管理(总共有多少变量,
地址在哪
,都是在编译时确定的;也就是说,
可执行码中没有类型信息
,只有地址,操作
的
字节
数
目
。
)
4.
优化
编译出来的执行码与汇编
的执行码
有
特征的
区别吗?
没有。
特别是在
编译器
优化之后。
无法通过执行码
,
区分汇编和
C
程序。
打个比方,一只
“
程序猫
”
在黑布笼子里,
在里面喵喵的叫,
无法通过它的叫声来判断它是
“
汇编猫
”
还是
“C
语言猫
”
。
从效率上来讲,
C
的多余代价
在哪里?
1.
编译的时间
2.
模块的堆栈操作
总之,经过优化的
C
程序
执行码与汇编效率几乎相同。
因为
从理论上来说,
C
并没有引入
运行时
的新机制
。
我理解的
C
语言只是一种
汇编的宏
而已。
C++
语言
(推荐《深度探索
C++
对象模型》)
C++
语言比
C
语言多了什么?
1.
成员函数
2.
类型继承体系
3.
虚函数虚继承
4.
模板
5.
涉及
到了多种编程范型
(
开始
更
抽象,
语言逐渐开始脱离冯氏结构。
)
其中,面向对象的思想,让程序与现实事物的关系更加紧密。
程序设计的负担,也因为
OO
与设计模式的流行,而变得轻松。
编程范型是什么?
就是一套指导思想行为准则。
(
例如,
C
是过程式,
Haskell
是函数式,
JAVA
是面向对象,
Python
是
简单的
大杂烩,
shell
是调用命令的
,
lua
是调用
c
程序的,
PHP
是写页面的,
ProLog
是线性逻辑
推理
的。
再例如,
UML
是描述规格
specification
的,
XML
是存储
数据的。
再
再例如,
CSS
是描述
网页
表现的,
HTML
是描述网页内容的。
javascript
比较神奇,不敢说
。
)
C++
有什么编程范型?
1.
过程式(使用
STL
的
类
C
语言编程)
2.
ADT
式(自定义抽象数据类型
,继承;但是不用
new
,不用
virtual
;拷贝构造
)
3.
面向对象式(使用
new
,使用
virtual
,需要指针
或引用
)
C++
编译器
是怎样实现的?
C++
开始有一个叫做
cfront
的编译器,
即把
C++
语言先翻译成
C
语言
。
然后再用
C
编译器来编译
,
C
的编译器并不知道此段代码是
来自
C++
还是
C
。
C++
语言特性分别是怎样实现?
简单说。
1.
成员变量:和
C
语言的
struct
类似
,最后也会被直接编译成地址
偏移
。
2.
成员函数
:使用特殊
函数名编码方案
翻译成
C
函数,并添加
t
his
指针
作参数
。
3.
类型继承体系
:
通过
C++
编译时的
Meta-Data
来实现。
即
在
编译时
,
编译器是
知道
类型信息
与
继承体系
的,但是翻译成
C
语言后就丧失了此类型信息。
4.
虚函数虚继承
:
为了支持多态,
这也是
“
面向对象
”
最重要的特性,使用了虚函数表和虚基类表。注意,运行时多态是
通过运行时
查表
实现
的
。
稍后详细说。
5.
模板
:通过代码复制的方式实现
。
C++
编译器的准则与
virtual
机制?
1.
首先,
C++
的编译准则,
希望做到与
C
一样
的效率
。
a)
没有
运行时调用
间接性。任何
数据在运行时都是一个
地址直接就访问到。
b)
没有运行时的
Meta-Data
。无需通过
Meta-Data
来访问某个复杂的
类层次。
c)
所有的数据都希望用
C
中
struct
来实现,
即在编译时就确定好对象及其成员
地址。
2.
以上,在
过程式范型
,与
ADT
范型
中都是成立的。
3.
但是,
在
面向对象范型
中,却遇到
问题:
a)
需要维系着同一个继承体系成员结构的一致性,只有这样,才能保证
运行时的多态性。即能够通过同一个地址
偏移
,访问到
父类或
子类
的
相同
数据
成员
、函数成员
,而不在乎
具体对象的类型。
b)
虚函数
i.
虚函数,运行时,每个有虚函数
的类型(哪怕是子类)都维持着一个虚函数表
,这已经是运行时的
Meta-Data
,
通过查表,即可找到对象自己
的
虚函数
。
ii.
例如下图中
clone
肯定是
object.__vptr__Base->#3()
,无论具体的对象
。
iii.
c)
多重继承
i.
如何处理后继的
base
基类
?由编译器判断指针类型并加上相应的偏移
d)
虚继承
i.
添加一个虚基类指针,指向共享部分
ii.
iii.
这样的缺点有两个
1.
虚基类的子类都要背负一个基类指针指向共享部分。如果继承了多个虚基类,还需要多个这样的指针。(
Microsoft
的解决方法是增加一个虚基类表,类似于虚函数表。)
2.
虚
继承链条
的增加,会导致间接访问的层次增加。
例如两
个菱形继承的串联。
头文件,库,源代码跨平台
1.
C++
确实在源代码的层次是可能跨平台的。
2.
也可以通过相同的头文件去访问不同平台的库。
3.
但是,不同操作系统中的不同的
API
大大增加了
跨平台的难度
。
4.
跨平台的责任留给了程序员
(充斥着大量宏的
C++
跨平台代码确实让人头疼。)
5.
编译器面对不同的系统也不敢
作为,它只是负责编译源代码,链接。
如何使用
C++
才能保证其高效性能?
1.
虚函数,虚继承,拷贝构造,这些是有额外负担的。
2.
用
一次
虚函数,
多了一次指针寻址的效率损失,
并且
相对于
inline
内联(另,
inline
是编译器优化的重头
)
,还损失了保存和恢复现场的效率。
3.
用一次
虚继承
,
也
多一次指针寻址的效率损失
。(另,
虚基类没有成员变量
没有虚函数
的时候
会被优化。
这也是
JAVA
可以多重继承接口
interface
的原因。)
4.
不要使用
virtual
在复杂
的
多继承,深层次继承中。
5.
virtual
编译时的
Meta-Data
需要处理更多,编译速度会较慢。
JAVA
语言
(推荐
本地
Java
代码的静态编译和动态编译问题
)
JAVA
语言比
C++
语言
多了什么?
1.
虚拟机
a)
跨平台
b)
动态编译
2.
没有指针
3.
没有类的多继承,有接口的多继承
4.
统一的库
从编译
来说,
JAVA
比
C++
迈出了一大步。
它的跨平台特性和动态特性
,
为
JAVA
自己以及
未来语言
都
提供了很多可能性。
虚拟机的好处
有什么?
1.
跨平台:在
OS
与字节码间隔了一层。实现了程序员无负担的跨平台。
2.
动态编译:
许多信息不必在编译后确定,
为动态特性提供可能,稍后详细说。
JAVA
编译执行的过程是怎样的?
1.
编译后产生一个基于堆栈的字节码
2.
JRE
在不同的
OS
上提供支持
3.
起初的
JRE
是解释执行的,效率低下。
a)
获取待执行的下一个字节码。
b)
解码。
c)
从操作数堆栈获取所需的操作数。
d)
按照
JVM
规范执行操作。
e)
将结果写回堆栈。
JAVA
是如何解决执行效率低下的问题呢?
使用
JIT
(
Just-in-time
)编译器进行动态编译。
JIT
是怎样运行的呢?如何解决了效率的问题?
如上图:
1.
每次按照一个
function
来编译。
转成中间表示,
并优化
其效率,再生成可执行码。
2.
编译器的编译线程和执行线程是分开的,应用程序不会等待编译的执行。
3.
分析框架
Profiler
会观察程序行为,
对频繁执行的
function
进一步优化
。
(例如
function
内部对象维持一个池不必每次生成。)
动态编译的优点有什么?
可以根据程序的行为,优化其代码
1.
例如
频繁执行的
function
——
热方法
2.
例如
arrayCopy
方法
,
如果每次都
拷贝大段内存
,
在指令
集
中有特别指令
可以加速
。
3.
例如类层次结构,多态的优化。
(
大多数虚调用都有其固定的一个目标,
JIT
因此
生成的直接调用代码比虚
表
调用代码的效率会更高。
)
动态编译的缺点有什么?
1.
大量的初始编译会影响程序启动时间。
2.
运行时候的编译,行为分析都需要花费时间。
3.
运行效率达到稳定需要时间
。
4.
实时
GUI
型的程序不能忍受
“
动态编译
”
和
“GC”
带来的延迟。
JAVA
如何解决实时的需求?
使用
AOT
(
ahead of time
)编译器
:预先编译成为可执行码。
AOT
的缺点
对于一些动态特性的支持效率低下
1.
反射机制
2.
运行时
类加载
JIT
与
AOT
的对比
总体来说,
JAVA
适合怎样的应用呢?
JAVA
比较时候需要长期运行的应用,例如
Web
服务器,
Daemon
服务。
函数式
语言
函数式语言通常有哪些呢?
1.
纯函数式语言
a)
Lisp
b)
Schema
c)
Haskell
d)
F#
?
2.
包含了函数式特性的语言
a)
Python
b)
Javascript
c)
JAVA
d)
C?
函数式
语言有哪些特性?
1.
函数无副作用
,只对输入输出有作用
2.
高阶
函数,
lamda
演算
。
(
这个
像
C
函数指针,但是它是高阶的
,即返回值可能也是函数
)
3.
没有过程,
类似
规格
说明
的
语法
,更容易理解
,自解释
。
4.
基于
list
的编程
,
函数更通用
。
5.
惰性计算(
这个很像
“
树形
DP”
)
6.
有对应的数学形式化表达
,
有可能
证明其正确性。
(
目标可能是保证
程序
没有
bug
。
)
总的来说,函数式语言,
向着更抽象
迈了一大步,
几乎与冯诺伊曼体系
断绝了关系。
函数式语言的劣势?
1.
效率不高
(因为其抽象
,
远离
了
冯诺伊曼体系
)
2.
平台以及开发环境都比较简单
。
3.
缺少推广,应用不广泛
逻辑程序设计
ProLog
语言,线性逻辑。人工智能语言。没有接触过。
动态性有哪些呢?
1.
多态性:
运行时
根据具体
对象来访问属于它的方法。
(而不理会指针的类型。)
2.
反射:运行时维系着类型结构
的
Meta-Data
。
3.
运行时类加载:
运行后再次加载新的
数据
类型和指令流
。
4.
动态链接:
OS
根据按需链接库文件。
编译语言 和 解释语言
语言本身并没有编译类型或者解释类型。(例如:
JAVA
也可以静态编译后成可执行码
。)
只有少数
运行时
特性是依赖于解释型的。
(
可能
需要运行环境的支持。)
为什么解释语言都需要虚拟机或者运行环境支持?
动态编译,运行时
Meta-Data
的保存,这些功能对于每个程序都是一致的
。
所以把它们分离
开来,
不必每个程序植入这些代码。
非脚本语言 和 脚本语言
脚本语言,我理解是负责调度
其他代码
的语言。
例如
shell
脚本
(调用命令)
,
lua
(调用
C
)
。
但是也不确定,例如
Python
。
跨平台
跨平台分为哪些层次?
1.
源码跨平台(
C
,
C++
,但是因为系统调用接口不同,程序员负担太大
,但是汇编却不是
。
)
2.
执行码跨平台
(
JAVA
,有些语言直接从源码解释执行,例如
Javascript
,
PHP
)
发展历史
(推荐
《
近看图灵碗
(
一
.
从苏黎世到巴黎
)
》
)
学术上有哪些实验性语言
?
1.
Fortran
2.
ALGOL
58
3.
ALGOL
60
4.
Lisp
5.
smalltalk
常用语言
过程式:
C
,
ALGOL
,
Delphi
,
Pascal
,
面向对象式:
C++
,
smalltalk
,
JAVA
,
函数式:
L
isp
,
Schema
,
Haskell
,
逻辑式:
Prolog
脚本?
PHP
,
Python
,
Ruby
结语
程序设计语言的目的是什么?
1.
控制数据
2.
控制
指令流
为什么大多数语言有控制流?逐行执行
+
跳转。这与我们的需求差很远(例如一个教务管理系统。)
逐行执行
的执行,很大程度是起源于冯诺依曼体系结构。
为什么类型申明在
C
语言中要与控制流隔离开来
?
因为在编译时,具体的类型信息,要转化成地址偏移
,然后替换
控制流中的类型变量
。
现在主流语言最基本的元素是?
是控制流 与 类型系统。
有没有语言它的类型结构,在运行时也可以改变?
Javascript
可以运行时给某个类添加新的数据成员。
许多后来的
语言在运行时都保存着类型信息的,
例如
Python
,
JAVA
。
+100
科创币
joyeep
2010/03/17
优秀的转贴
来自:
计算机科学
/
软件综合
4
0
全部
只看作者
warmonkey
16年10个月前
IP:未同步
201410
1楼
我总算看懂了。。。。
加载全文
引用
评论
0
novakon
16年10个月前
IP:未同步
201436
2楼
好帖,加精大大的要
加载全文
引用
评论
0
joyeep
16年10个月前
IP:未同步
201448
3楼
深度探索C++对象模型 是好书,读了一遍,建议从后面往前看,而不 要顺着往后看
加载全文
引用
评论
0
phpskycn
16年10个月前
IP:未同步
201949
4楼
N条要求没达到,看懂70%的路过
对于MFC抓狂ing
Visual C++哪都好,就是写窗体太累了
难道该VB+C++一起上?
加载全文
引用
评论
0
全部
只看作者
在列表中查看
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
编辑
删除
{{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
保存
取消
我也是有底线的
保存中...
保存