标签归档:编程

malloc 从哪里得到的内存空间

引子

在计算机高级编程语言中,C 语言相对来说是一种低级语言,从某种意义上讲,C 语言就是现代的“汇编语言”。说 C 语言低级很大程度上是因为 C 程序员需要手动管理存储,具体反应在公认最难最容易出错的指针上。比如编写 C 程序时,经常会出现莫名奇妙的段错误,并且内存泄漏会在不知不觉的情况下发生,直到耗尽你的计算机内存资源为止。更危险的则是缓冲区溢出,使程序非常容易受到攻击。

发明 C++ 的一个目的是为了提升 C 语言的抽象能力,还有一个目的就是为了消除指针,但 C++ 显然没有做到这一点。Java 则继承了 C++ 的遗愿,彻底的消灭了指针。Java 等高级语言采用严格的内存管理,动态的垃圾回收等机制使得程序员不用去手动管理内存,不用和底层打交道。但 C 语言的地位仍是无法取代的。在必须和底层打交道的时候,就得使用 C 语言(有时候甚至要用汇编语言),比如现代操作系统都是用 C 语言编写的。另外,高级语言在引入高级特征的同时,效率上就会有所损失,在非常强调执行效率的地方,C 语言通常是首选。

继续阅读

计算机中的大端法和小端法

时隔一年时间再一次看 CSAPP(Computer Systems: A Programmer’s Perspective, 2/E, 中文译名:深入理解计算机系统),正是这本书把我带入到计算机世界。在读第三章时某段时,对第二章中寻址和字节顺序中所讲的大端法与小端法的一些细节感到困惑。于是查了一些资料,主要是 Wikipedia 上的 Endianness 词条,在这里做一下总结。

基本概念

在计算机内存中,通常是以字节(Byte),也就是 8 个位(Bit)为基本存储单元(也有以 16 位为基本存储单元的)。对于跨越多个字节的数据类型(比如 int 长 4 个字节),如何在内存中对这些字节进行排序有两种常见的方法:大端法和小端法。不管是大端法还是小端法存储,计算机在内存中存放数据的顺序都是从低地址到高地址,所不同的是首先取低字节的数据存放在低地址还是取高字节数据存放在低地址。

  • 若首先取高字节的数据存放在低地址,则是大端法;
  • 若首先取低字节的数据存放在低地址,则是小端法。

Endianness

至于大小端法,只是一种习惯,没有优劣之分,只可惜在计算机发展史上没有形成一个统一的标准。

词源

大端法和小端法的英语原文分别为 Big-endians 和 Little-endians, endian 一词来自乔纳森·斯威夫特的小说格列佛游记。下面摘自《深入理解计算机系统》

旁注:“endian”的起源

下面就是Jonathan Swift在1726年如何描述大、小端之争的历史的:

“……我下面要告诉你的是,Lilliput和Blefuscu这两大强国在过去三十六个月里一直在苦战。战争开始是由于一下原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按原来的方法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道命令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由Blefuscu的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻救避难。据估计,先后几次有一万一千人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派一直是受禁的,法律也规定该派的任何人不得做官。”(《格列佛游记》第一卷第4章)

在他那个时代,Swift是在讽刺英国(Lilliput)和法国(Blefuscu)之间持续的冲突。Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了。

字节序还是位序

大端法和小端法指的是字节在内存中存储时的排列规则,而不是数据中的位的排列规则。也有以位序排列的机器,但很少见。另外,再次明确一下,大端法或小端法是数据在存储时的表现,而不是在寄存器中参与运算时的表现。

浮点数的字节序

在所有机器上,浮点数在存储时的字节顺序是和整数的字节顺序一样的,所以在进行网络传输时,可以把浮点数当作整数进行字节序转换。但在历史上,曾经有段时间因为 IEEE 并没有规定浮点数在网络上传送的标准,所以浮点数都是以大端法进行存储的。

判断大小端法的方法

Linux 操作系统中使用了一个联合体(union)和宏进行判断

static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };

#define ENDIANNESS ((char)endian_test.l)

相当巧妙,不是吗?

网络上的字节序

对于大多数程序员来说,机器的字节顺序是完全不可见的。但有时候,字节序会成为问题,特别是在不同类型的机器间传送数据时。比如小端法机器产生的数据发送到大端法机器时,字节就会成为反序。所以制定了网络字节序标准,网络字节序是大端法。在进行网络编程时,要确保数据在进行发送时需要转换为网络序,接受方再转换为自己的内部表示。这个过程涉及到六个函数:

#include<sys/types.h>
#include<netinet/in.h>

uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);

uint32_t htonl(uint32_t hostint);
uint32_t ntohl(uint32_t netint);

/* 一些系统并没有提供下面两个函数,需要自己实现 */
uint64_t htonll(uint64_t hostlong);
uint64_t ntohll(uint64_t netlong);
符:处理器体系 (摘自维基百科
  • x86,MOS Technology 6502,Z80,VAX,PDP-11等处理器为Little endian。
  • Motorola 6800,Motorola 68000,PowerPC 970,System/370,SPARC(除V9外)等处理器为Big endian
  • ARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC and IA64的字节序是可配置的。

我爱 Python

哦,别误会了,我说的 Python 不是这玩意,而是一种编程语言。

这几天用 Python 语言完成了一个项目,包括一个数据分析统计模块和一个简陋的 GUI (图形用户界面)模块,大约一千行代码左右。这是我第一次用 Python 写这么大的程序(对我来说算是够大的了)。从这个项目中充分体会到了 Python 语言的强大和易用。

一个语言是否简洁,有多简洁,从它的 hello world 程序中就可以看得出来:

print 'hello world'

在我所接触到的编程语言中,Python 代码最接近自然语言。强制缩进和一种问题只有一种解决办法的思想使得 Python 代码很整齐,看起来和伪代码一样。虽说这样少了自由度,但再也不用去管那些大括号匹配,行末位分号等,你会对此心存感激的。Python 是真正的为人类设计的语言。

Python 是一种动态语言,也就是说没有了编译步骤,代码就是程序,程序就是代码。并且在使用变量时用不着声明,想用就用,不用那么多废话。在使用一个变量时,也不用太考虑类型问题,直接用就是。

Python 有一个涵盖面很广的标准库,很多问题都已经在此解决了。我想如果这个项目我用 C/C++ 语言写的话,那么几乎要自己从新实现这些 Python 标准库就提供的功能。加上 C/C++ 语言的啰嗦程度,估计代码行数要增加一个数量级。

还有一个是 Python 没有指针,不用手动管理内存。Python 内建的内存管理和垃圾回收机制很完善,再也不会遇到莫名其妙的段错误了。

Python 的好处太多了,可以看看维基百科的介绍。

Python 是一门很容易学习的语言,也被推荐为入门者应该学的第一门语言。事实上,如果你是一名有经验的程序员,那么你能在两个小时内学会 Python 语言的语法并写出有用的程序。简明 Python 教程 是一个很不错的学习资料,深入学习的话可以看看 Dive Into Python 中文版Python 的官方网站是你应该常去的地方,也是各种文档资料最多的地方。

Python 可以说是一个很“酷”的编程语言,它被列为黑客应该学习的五中编程语言之一,它的资深使用者几乎都是很厉害的程序员。它被使用的也很广泛,豆瓣网的后台开发语言就是 python, Google 主要使用的三种编程语言也包括 Python.

Python的创始人为吉多·范罗苏姆(Guido van Rossum),关于他还有一段有意思的故事:Guido 去 Google 面试,简历只有一句话:I wrote Python (我写 Python),结果面到第10轮 Google 才明白过来这句话的真正意思。

当然每种编程语言都有它合适的领域,相对来说 Python 是一种开发效率较高的语言,但其运行效率则相对较差,如果和 C 语言写出的同样功能程序相比的话,有时候甚至要慢上几个数量级。在一些项目中,牺牲运行效率来提升开发效率还是很直当的。比如在我的这个项目中,写一个桌面程序,对于用户来说,一毫秒和一秒的反应时间真没什么区别。不过 Python 语言和 C 语言结合的很紧密,一些对效率要求很高的模块可以用 C 语言来写,Python 执行时导入该模块即可。实际上,Python 本身就是 C 语言写的。由于 Python 的代码即程序的特点,所以如果算法需要保密的话,也可以用 C 来写,这样别人就看不到你的源码了。

有很多工具可以将 Python 程序转换为 Windows 可以在不用安装 Python 解释器直接执行的 exe 文件。我根据这篇文章:使用py2exe打包pyqt程序为exe 提供的方法成功将 PyQt 程序打包成了 exe.

另外,Python 语言是一个由社区驱动的自由软件,任何人都可对其做贡献,它的源码也是很好的学习 C 语言资源。

延伸阅读:

每个程序员都应该学习使用Python或Ruby

Zen of Python — 蟒之禅!

PyQT 介绍和一些资源

这几天学习了 PyQt , 照猫画虎的做出了一个图形界面。

Python 是功能很强大的脚本语言,Qt 是跨平台的界面开发语言,二者的结合就是PyQt, 它是 Python 语言的 GUI (图形用户界面)编程解决方案之一,而 QT 是由诺基亚开发的应用软件框架。使用 PyQt 编写程序图形界面可以在不修改代码情况下在很多种平台比如 Windows, Linux 和 MacOs 上运行。

PyQt 官方网站:http://www.riverbankcomputing.co.uk/software/pyqt/intro

安装:

如果你使用的是 Windows, 需要首先安装 Python, 如果你对这篇文章感兴趣的话你肯定已经安装了 Python. 然后到 PyQt 官网上下载一个 Windows 安装包进行安装,注意应根据你安装的 Python 版本号进行选择。 PyQt 的 Windows 安装包已经包含了一份 Qt, 安装的时候注意选择你安装 Python 的目录。

如果你使用的 Ubuntu Linux, 那么已经默认安装了 Python, 运行下面命令就可以自动的安装所依赖的软件包:

sudo apt-get install python-qt4

然后运行命令:

sudo apt-get install python-qt4-doc

安装 PyQt 的文档和示例。

Eric 则是由 Python 开发的一款支持 PyQt 的 IDE, 可以很方便的使用 Qt Designer 设计界面,安装和使用可以看这篇文章:Eric+PyQt打造完美的Python集成开发环境。也许在编写大程序时 IDE 是很有用的,但我更喜欢用一个自己喜欢的文本编辑器手工 Hack.

学习资源:

PyQt Reference Guide

The PyQt4 tutorial

Rapid GUI Programming with Python and Qt

GUI Programming with Python: QT Edition

PyQt – PythonInfo Wiki

不过上面都是英文的,再次证明了学好英文对搞计算机的重要性。中文资料很少,有一个翻译了 The PyQt4 tutorial 的资源:

http://www.czug.org/python/pyqt4/

还有这个:

http://code.google.com/p/pyqt-doc-cn/

http://www.ibm.com/developerworks/cn/linux/l-qt/

在安装好 PyQt 后,程序自带的一些例子也是很好的学习资源。

Windows 中例子位于:python目录Libsite-packagesPyQt4examples

Linux 中例子位于:/usr/share/doc/python-qt4-doc/examples

在编写程序时,查看官方文档很有用,列出了所有模块中对象的可用方法、参数和它继承的对象等

我在使用 QtGui.QFileDialog.getOpenFileName 方法时,遇到如果文件路径中包含汉字时打开文件会出错的问题,估计又是因为该死的字符编码。我没有搜索到解决方法,最后自己试了几次,用如下代码解决了问题。我不知道为什么,但它能正常工作 :-)

fname = str(QtGui.QFileDialog.getOpenFileName(self, u'选择文件',
	'/home', u"ACMi 文件(*.acmi)").toLocal8Bit())
f = open(fname, 'r')

多平台兼容时字符编码问题

我把自己在 Win 下写的 Python 程序拿到 Linux 下运行,遇到了一些问题。

第一个问题是汉字乱码问题。问题出现在 Win 下汉字的默认字符编码格式是 ANSI 格式,而 Linux 下默认使用 UTF-8 格式。如果你用的是 Ubuntu, 可以看看这篇文章:Gedit中文乱码。如果你想让你的程序能在多平台下正常运行,最好在编写程序时使用通用的 UTF-8 格式编码,或者在你的代码中不要出现除了 ASCII 码之外的字符。

第二个问题:在 Linux 的脚本程序第一行中写类似于下面的代码:

#!/usr/bin/python

可以指定运行脚本的程序,从而可以直接运行脚本文件。但是我的程序并没有直接运行成功,shell 提示找不到解释器文件。只能以类似如下命令方式运行:

python test.py

也就是说第一行代码没有起作用。

猜测出现这个问题是因为 Win 和 Linux 下文本换行符格式不一样。在 Linux/UNIX 下,换行符为 ‘n’, 而 Win 下为 ‘rn’, Mac 下为 ‘r’, 所以 shell 在运行文件时,’/usr/bin/python’ 后多出了一个字符 ‘r’, shell 按照这个文件名当然找不到。解决办法:在编写代码时以 UNIX 格式新建文件,使用 notepad++ 文本编辑器可以很容易做到这一点。

但在我使用了 UNIX 格式新建文件和 UTF-8 文本编码格式保存后程序还是无法直接运行。我试着以UTF-8 无 BOM 格式编码后问题得到解决。查找了资料,了解到:BOM (Byte-Order Mark),字节顺序记号,中文也叫字节顺序记号。对于 UTF-16 和 UTF-32,BOM 的作用是在文件开头加上三个字节来标识文件的字节序,即采用的是大端法还是小端法。但对 UTF-8 来说,没有字节序的问题,BOM 的作用只是来标识这是一个 UTF-8 编码的文本文件。在 UTF-8 中,BOM 在文件开头占三个字节为 EF BB BF (十六进制)。在类 UNIX 系统中,UTF-8 BOM 这种作法则不被建议采用。但是在windows系统中,它是默认存在的。UTF-8 BOM 可以在不知不觉间导致一系列莫名其妙的问题。

总结一下

如果你想让你的代码不但能在 Win 下,也能在 Linxu 下都正常运行(其他平台没有测试),那么最好以 UNIX 格式新建文件,使用 UtF-8 无 BOM 格式编码。Win 下推荐使用 notepad++ 文本编辑器

扩展阅读

字符编码笔记:ASCII,Unicode和UTF-8 —— 阮一峰

UTF-8文件的Unicode签名BOM(Byte Order Mark)问题

Pyqt 学习成果

今天读了 The PyQt4 tutorial, 学习了一些基本的用法。另外花了两个小时左右的时间,又看了一遍 简明 Python 教程,复习一下 Python 语言。下周要交计算机图形学作业,就拿来练练手。本来想做成一个带菜单的界面,整合到一块,但调试了很久没有成功,就只做了最基本的。做的不是很完美,一些接口不知道怎么用。

今天太晚了,下次再介绍安装、配置和一些资源,睡觉……