C++能否成为你新的脚本语言

一些背景

  第一个我真正喜爱的编程语言是 C。我花了不少时间才找到它:当我还是一个孩子,我就开始在珍贵的ZX Spectrum上使用 Z80 汇编。那些日子是你能够真正掌握你的电脑的时候,你不需要苹果,谷歌,微软或者其他任何人的允许就能写一个程序。我在漂亮的128K ZX Spectrum +2上学习了在超出 CPU 寻址空间时对内存块分页。直到我进入大学,我才拥有一台 IBM PC 机 。我玩遍了电子表格,试图修复现存的 Fortran 程序,用土耳其字符给键盘驱动打补丁,还学了点 Pascal 语言。之后,在我就职于土耳其中央银行期间,我又学习了 SQL 和 APL

  我一直对 C 语言有所耳闻,但我一直没有接触到一款C语言编译器。直到我到康奈尔大学拥有了一个Unix 账号之后,我编译了我人生中的第一个 hello.c 文件,不久之后,我有了第一台电脑……我在 DOS 分区上安装了 DJGPP 编译器,构建了我人生中第一个 Linux 内核(我第一个发行版是 Debian),并且开始学习 C 语言。Plauger 的 "Standard C Library" 是我最喜欢的书。

  当我开始享受用 C 编程的时候,C++ 已经广泛应用超过十年了。所以,我下一步使用 C++ 看起来是很自然的一步了。

  除了……好吧,除了 C++ 是一片混乱。那段时间,所有人都被继承层次深深吸引了,每个人都在编写精心设计的字符串类。大多数硬盘都太慢,不能在有限的时间内编译出可靠的 C++ 库(好吧,我有点夸张了),大部分 CPU 都在试图实例化模板中融化了,大部分人,那些假装 C++ 程序员的 C 程序员们,差点就把malloc 的返回值给扔了。

  在那时,我正忙于试图建立定制化的网络经济实验,看起来 Java 似乎很有优势。至少,它不需要麻烦地拼凑出一个对话框。产生少量的 socket 连接,并且使你的应用编译和运行在多种多样的系统上。当然,AWTSwing 都很丑陋且笨重,但对我的目的来说,那没关系。

  但是,仅仅是因为不能在实验室之外运行我的实验(因为在实验室已经配置了所有电脑,java应用程序运行不会有问题)。所以我快速的把FreeBSD部署 到了一台拥有100Mhz奔腾处理器,16Mb内存,在角落里收集灰尘的机器上,并搭建了一个拥有perl模块(mod_perl)的Apache服务 器,然后就能工作了。那就是我爱上Perl的时候。

  那份爱完全起源于实用的原因,我并不是认为Perl特别的完美,并且那时候我认为包括其他许多语言都不是很完美,他们中的每一个都有自己的瑕疵。

  Perl总是能减少我必须解决的特别问题的工作的数量,有些是因为语言特性,但大部分是因为 CPAN

  举例来说,作为一个 Perl 程序员,解析 HTML 作为 HTML 是一个解决方案。我必须决定,要么就构造整个树, 或者使用流化的方式。在某些情况下,前者是具有优势的,但后者的好处是可以使内存的需求降至最低,即使是在这个年代,如果你处理 HTML 文档以兆字节方式还是可以奏效的。不论哪种方式,这些工具都不会在无效的 HTML 上被卡住,并在非 XML 的有效 HTML 上运作良好。

  还有,Perl 提供可移植性。如果我不需要操作系统特定的功能,不用任何修改地方,我的 perl 代码就可以运行。

  当我写了一些类,并为它们做了封装,也不会有复杂的架构。

C++ 涅槃

  在过去的数年,C++如获新生。许多聪明人已经开始意识到需要向C++程序员提供同时涵盖 work of the ISO committee和 boost的构建模块。

  在真实环境下,仍然有90%的菜鸟生成C++程序员就是没有意识到new是一个合法符号的C程序员。在这方面,C++与Perl非常相似:大部分人写过 Perl代码的人也没有意识到Perl不是C、Java、Python、shell、Awk或者其他你可以列举的语言。

  但是,当你看到新C++标准中的新东西,以及编译器不断实现这些特性的新闻时,我们无法抑制住内心的兴奋和好奇。

单词计算练习

  这是一个简单的练习,使用 C++ 或者 Perl 并且不依赖外部库,所以这是一个很好的起点。

  这是 Perl 版本,供您参考:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

#!/usr/bin/env perl

use strict;

use warnings;

run(\@ARGV);

sub run {

my $argv = shift;

my @counts;

for my $file ( @$argv ) {

my $count = -1;

eval {

$count = word_count($file);

1;

} or warn "[email protected]";

push @counts, {

file => $file,

word_count => $count,

};

}

for my $result (@counts) {

printf "%s: %d words\n", $result->{file}, $result->{word_count};

}

}

sub word_count {

my $file = shift;

my %words;

open my $fh, ‘<‘, $file

or die "Cannot open ‘$file‘: $!";

while (my $line = <$fh>) {

my @words = split ‘ ‘, $line;

$words{ $_ } += 1 for @words;

}

close $fh;

my $word_count;

$word_count += $_ for values %words;

return $word_count;

}

  而且,这是我最大的付出在转化 Perl 到现代风格的 C++ 上面。我没有尝试写特别搞笑的代码:只是和 Perl 一样,我把重点放在写代码上面,使得我感到非常自然,同时确保两个程序都做大致相同的事情。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

#include <cerrno>

#include <cstdio>

#include <cstdlib>

#include <fstream>

#include <iostream>

#include <numeric>

#include <unordered_map>

#include <string>

#include <vector>

using std::accumulate;

using std::cerr;

using std::cout;

using std::endl;

using std::ifstream;

using std::make_pair;

using std::pair;

using std::strerror;

using std::string;

using std::unordered_map;

using std::vector;

int word_count(const char *const file) noexcept(false);

int main(int argc, char *argv[]) {

vector< pair<string, int> > counts {};

for (auto i = 1; i < argc; i += 1) {

try {

counts.push_back(make_pair(argv[i], word_count(argv[i])));

} catch (const string& e) {

cerr << e << endl;

counts.push_back(make_pair(argv[i], -1));

}

}

for (auto& result : counts) {

cout << result.first << ": " << result.second << " words" << endl;

}

return 0;

}

int

word_count(const char *const file) noexcept(false) {

errno = 0;

ifstream fp(file);

{

// Does fp.fail() preserve errno?

int save_errno = errno;

if (fp.fail()) {

throw("Cannot open ‘" + string(file) + "‘: " + strerror(save_errno));

}

}

unordered_map<string, int> word_count {};

string word;

while (fp >> word) {

word_count[word] += 1;

}

fp.close();

return accumulate(

word_count.cbegin(),

word_count.cend(),

0,

[](int sum, auto& el) { return sum += el.second; }

);

}

  20 行代码用于 #include 和 using 声明可能看起来有点多,但是我抬眼 using namespace std,也讨厌不断地输入 std::... 更多的是因为我喜欢较短的代码行。

  首先要注意的是没有看得见的显式的内存分配。容器集装箱管理自己的内存。

  第二,这是一个大问题:我们有自动导入(autovivification)!

?


1

2

3

4

5

6

unordered_map<string, int> word_count {};

string word;

while (fp >> word) {

word_count[word] += 1;

}

  第三,我们有 lambda 表达式:

?


1

2

3

4

5

6

return accumulate(

word_count.cbegin(),

word_count.cend(),

0,

[](int sum, auto& el) { return sum += el.second; }

);

  在这背后,accumulate 将内部变量初始化为 0,并调用一个匿名函数,其最后一个参数指定为当前值,以及word_count的下一个元素。

那么现在呢?

  然而,并非所有事情都是那么美好。虽然boost libraries 库上填补了很多空白,在构建模块时标准库也十分给力,但是它很难与用 Perl 和 CAPN 混合编写的那种跨平台、可移植代码时的便利性相提并论。

  举个例子,我能到处找得到一个与平台无关的库,这个库可以为我解析或者创建 Excel 文件而不需要 Excel 应用?并且这个库可以像 clang,g++ 和 cl 那样方便编译?这显然找不到。

  我确实非常感谢那些工作在标准委员会和那些开发编译器和库的人,因为有了他们我在写 C++ 代码时不是那么费力。

  这让我感到十分舒服,与此同时我又能够尽情去折腾我的电脑。

  正因为如此,我很感激。

  你可以在 /r/cpp评论这篇文章

时间: 2024-10-10 20:33:10

C++能否成为你新的脚本语言的相关文章

Streem:Ruby之父开发的新脚本语言

刚看到Ruby语言的开发者松本行弘(Matz,全名是Yukihiro Matsumoto)又启动了一门新语言的开发,名叫Streem,还处在非常原始的阶段,只有三个文件,代码在GitHub上. 看Matz自己的说明,Streem是一种基于流的并发脚本语言,类似于shell/awk/,但语法更为丰富, 用Streem可以这么写一个简单的cat程序: STDIN | STDOUT 一个简单的FIZZBUZZ程序 seq(100) | {|x| if x % 15 == 0 { "FizzBuzz&q

Java SE 6 新特性: 对脚本语言的支持

2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不错的提升.与 Tiger 在 API 库方面的大幅度加强相比,虽然 Mustang 在 API 库方面的新特性显得不太多,但是也提供了许多实用和方便的功能:在脚本,WebService,XML,编译器 API,数据库,JMX,网络 和 Instrumentation 方面都有不

JDK1.7新特性(3):java语言动态性之脚本语言API

简要描述:其实在jdk1.6中就引入了支持脚本语言的API.这使得java能够很轻松的调用其他脚本语言.具体API的使用参考下面的代码: 1 package com.rampage.jdk7.chapter2; 2 3 import java.io.FileWriter; 4 import java.io.IOException; 5 6 import javax.script.Bindings; 7 import javax.script.Compilable; 8 import javax.

java脚本语言学习心得

第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 第一篇技术博客,一定要认真! 好了,进入正题: 一 什么是脚本语言? 程序的运行方式有两种:编译运行和解释运行 1.1 前者的典型代表是java, 从文件角度看分为三步: write[编写]: a.java文件(拿个记事本就能写,扩展名是.java), compile[编译]: 编译(cmd命令是java a.java,ide集成了编译器运行之前自动编译)之后产生了a.class文件(是一堆二进制码,人看不懂,是给虚拟机看的) 运行[r

动态网页脚本语言

在ASP .PHP.JSP环境下,HTML代码主要负责描述信息的显示样式,而程序代码则用来描述处理逻辑.普通的 HTML页面只依赖于Web服务器,而ASP .PHP.JSP页面需要附加的语言引擎分析和执行程序代码.程序代码的执行结果被重新嵌入到HTML代码中,然后一起发送给浏览器.ASP .PHP.JSP三者都是面向Web服务器的技术,客户端浏览器不需要任何附加的软件支持. 二.技术特点: (一)ASP的技术特点: 1. 使用VBScript .JScript等简单易懂的脚本语言,结合HTML代

JavaScript--基于对象的脚本语言学习笔记(二)

第二部分:DOM编程 1.文档象模型(DOM)提供了访问结构化文档的一种方式,很多语言自己的DOM解析器. DOM解析器就是完成结构化文档和DOM树之间的转换关系. DOM解析器解析结构化文档:将磁盘上的结构化文档转换成内存中的DOM树 从DOM树输出结构化文档:将内存中的DOM树转换成磁盘上的结构化文档 2.DOM模型扩展了HTML元素,为几乎所有的HTML元素都新增了innerHTML属性,该属性代表该元素的"内容",即返回的某个元素的开始标签.结束标签之间的字符串内容(不包含其它

题外话:Lua脚本语言存在的意义

纯属个人见解. 大致来说:c/c++执行效率高,游戏中一些性能敏感的复杂计算需要用c/c++来实现,防止游戏卡顿和低帧率.这些复杂计算包括战斗逻辑,复杂AI,骨骼动画蒙皮骨骼点的坐标计算等等.但c++是一种比较复杂的编程语言,开发效率较低.嘛,不过这不是主要问题,对于商业手游项目只用c++开发,是致命的.这一点在后边lua具体说明. lua是脚本语言,执行效率不及c/c++,往往用来实现性能不敏感的游戏逻辑,比如窗口界面等等.另外lua语法简单,开发效率高,没有编程背景的策划花精力后也可以掌握,

[Java面试九]脚本语言知识总结.

核心内容概述 1.JavaScript加强,涉及到ECMAScript语法.BOM对象.DOM对象以及事件. 2.Ajax传统编程. 3.jQuery框架,九种选择器为核心学习内容 4.JQuery UI插件 5.jQuery Ajax编程 6.jQuery第三方插件 7.反向Ajax编程(彗星) 一.JavaScript基础加强 JavaScript是在浏览器内容运行,无需编译.解释执行动态脚本语言,是一种弱类型语言,所有变量使用var定义. JavaScript的3个组成部分分别为:核心(E

Cocos2d-x 脚本语言Lua中的面向对象

Cocos2d-x 脚本语言Lua中的面向对象 面向对象不是针对某一门语言,而是一种思想.在面向过程的语言也能够使用面向对象的思想来进行编程. 在Lua中,并没有面向对象的概念存在,没有类的定义和子类的定义.但相同在Lua中能够利用面向对象的思想来实现面向对象的类继承. 一.复制表的方式面向对象 --Lua中的面向对象 --[[ 复制表方式面向对象 參数为一张表.通过遍历这张表取值,赋给一张空表,最后返回新建的表.来达到克隆表 ]] function clone(tab) local ins =