二进制文件和文本文件的详细以及如何生成二进制文件?
技术随笔 2010-05-01 19:13:56 阅读226 评论0 字号:大中小 订阅
这个问题一直困扰了很多年,可能是我没有认真的去思考。我相信很多人可能和我一样很纠葛,到底编译器也好,汇编器也好是如何工作的呢?到底怎么回事?为什么会运行呢?这是让我们这些看着windows学习电脑的人真的很难去理解计算机的内部结构。其实,这一切都只是障眼法,下面我就来给大家细细说说我对计算机的理解。
解答1:编译器是怎么回事?
所谓编译器,顾名思义就是将一种文本格式转换成另一种文本格式。比如将字符串 echo "hello"; 转换成 printf("hello"); 这其实是php语言转成c语言的一种表示。这只是一种简单的描述,其实很大一部分的编译器是将源语言转换成了汇编语言。下面我们来看看 C 语言中的经典 hello word,通过gcc编译后生成的汇编是怎么回事。
c语言源码:
#include<stdio.h>
int main() {
printf("hello world\n");
}
通过编译器后,编译器把这个翻译成了另一套字符串,其实就是汇编语言:
.file "hello.c"
.section .rodata
.LC0:
.string "hello world"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16,%esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
movl $.LC0, (%esp)
call puts
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2"
.section .note.GNU-stack,"", @progbits
这就是编译器做的工作了,其实这应该可以理解是吗,其实就是从一种字符串模式到了另一种字符串模式。但是很多人一定和我一样在思考,字符串模式的转变我会,但是从字符串转到二进制如何转其实我们的大脑真的被这些东西所迷惑了,都错了,字符串是什么?字符串其实也是二进制啊,只不过字符串它不能执行而已。当我们查看字符串的16进制的时候,其实和二进制的16进制一样,只是我们人为的给字符串赋予了一个这样的一层
显示方式。而二进制码之所以没有这层皮,是因为他有了另一层含义。汇编器其实和编译器做的动作是一样的。只是抽象的层次不同。这里有点绕是吗?其实不绕。当我们编译的时候,我们发现了文本文件要比可执行文件小很多,文本文件比汇编文件小6.5倍。而比二进制要小70倍左右,也就是说一个60字节的文本文件编译成汇编是400个字节左右,再生成二进制大概是4k左右了。
那这到底说明了什么呢?
其实是这样的,所谓的二进制其实和我们一般说的 ASCII 中的FF,0F是一样的,只不过二进制符合的不是ASCII的这套显示或者作用标准,它采用的是计算机cpu的处理标准。比如 \x41 在ASCII中表示的是A,而到了计算机cpu那里他可能是另一个意思,
那么你又会觉得奇怪,那么为什么文本可以显示,而二进制却不能呢?因为文本文件是通过文本文件查看器去重新给文本文件进行处理然后显示的,并不是我们想当然的"直接打开"就能看见,至少也要通过notepad吧?!而二进制进行运行,则是不通过其他软件的,直接丢
给cpu的(当然,你也可以用notepad打开二进制文件,只不过显示的是杂乱的ASCII字符和控制符)。有些人又会问了,错了吧,windows的二进制丢到linux下能用吗?其实这不是错,windows的二进制丢到linux下之所以不能运行,并不是二进制本身的问题,而是因为linux里没有windows的库,二进制文件运行的时候缺少必要的库才无法运行。所谓的库,其实就是调用系统资源或者本身就是系统资源的一种程序包(比如显示,接受键盘,窗口啊,等等等等)。和二进制代码有关的唯一的一方面其实就是cpu。因为不同的cpu处理的二进制的指令是有区别的。
其实,说穿了,所谓的计算机软件,就是对计算机硬件的一次次的抽象,让它更接近于人类的思考方式和使用习惯。这其实和我们生活中的很像,比如,我们把硬件比作是树木(当然硬件的材料属性并非木头的属性,它的属性比木头要更全面,可以很坚硬可以很柔软),那么二进制就是木头,可是木头毕竟只是木头,虽然是很好的材料但是单单一颗木头有什么用呢?于是,就有一些最早的程序员用手去处理这个木头,做出了一些简单的凳子椅子。于是程序员们就像,不如用做出一个木头匕首来切木头,这样不是比手抓更好吗(我前面说了硬件的属性比木头更全面,可以很硬也可以很软)?汇编就好比是这么一个匕首。用着用着,人们觉得匕首砍木头,虽然可以做出很精细的东西,但是砍大件不行,于是就用匕首加上手工制
16进制字符串转16进制数组作出了一把短刀,这就是C语言吧,然后他们在短刀里增加了一些齿牙,让比短刀更有杀伤力,这就是C++。可以他们发现,这个短刀虽然好,但是它只能砍一种树(因为这种树的木头做的短剑只能砍这种树),于是他们用两种木头各做了一面做了一把短剑,短剑虽然有两面,但是剑的杀伤力明显比刀要小。这就是我们说的Java。
那么操作系统是什么呢?操作系统我们可以理解为一个工具包,这个说明书里面写了各种用木头制作工具的说明并且提供了很多基础工具和小配件(我们看起来是不是很像木匠了,桌面上放了许多用木头做的小工具)。
然后我们要做的就是用这些配件和工具来做出我们的板凳啊,家具啊,各种各样的东西。
二进制文件和文本文件详解
2010-07-30 19:10:00| 分类: C++ | 标签:二进制文件 存放 文件 换行 文本 |字号大小 订阅
对于文件操作中的二进制文件和文本文件的读写,相信还有很多人有疑问,这两种方式有什么不同呢?首先我们记住文件只是计算机内存中以二进制表示的数据在外部存储介质上的另
一种存放形式,对于文本文件来说,它只是一种特殊形式的文件,它所存放的每一个字节都可以转换为一个可读的字符,就是说文本文件存放数据时,存放的是字符的ASCII码。
有点需要注意,按照文本方式向文件中写入数据时,遇到“换行”符,则会转换为“回车-换行”符,存储,即当存放10(换行符)时,在文件中会存放 13 (回车)和10(换行),同时存储的文件就多了一个字节了,而读取文件的时候,遇到13和10,也会合成ASCII10即换行符读取,而当按照二进制文件模式向文件中写入数据时,就会按照数据在内存中的存储形式原样输出到文件中,即存放10时,不会转换为13和10, 所以如果以二进制方式向文件写入10时,当以文本方式(例如记事本)打开文件时,看到的会是一个小黑快,而不是换行符,因为在文本文件中,只有遇到13 和 10的组合时才会转换为换行符。
为了加深理解,我们来看一道常见的面试题:给你一个整数,例如123456, 将这个整数保存到文件中,要求当用记事本打开文件时,显示的是123456。
应该怎么想这题呢?首先记事本是属于文本模式的,所以会将数据作为ASCII码,然后转换为对应的字符,所以在存入数据的时候必须是存放123456这几个字符对应的ASCII码;看看123456各个字符对应的ASCII码:
“1” ->49;
有点需要注意,按照文本方式向文件中写入数据时,遇到“换行”符,则会转换为“回车-换行”符,存储,即当存放10(换行符)时,在文件中会存放 13 (回车)和10(换行),同时存储的文件就多了一个字节了,而读取文件的时候,遇到13和10,也会合成ASCII10即换行符读取,而当按照二进制文件模式向文件中写入数据时,就会按照数据在内存中的存储形式原样输出到文件中,即存放10时,不会转换为13和10, 所以如果以二进制方式向文件写入10时,当以文本方式(例如记事本)打开文件时,看到的会是一个小黑快,而不是换行符,因为在文本文件中,只有遇到13 和 10的组合时才会转换为换行符。
为了加深理解,我们来看一道常见的面试题:给你一个整数,例如123456, 将这个整数保存到文件中,要求当用记事本打开文件时,显示的是123456。
应该怎么想这题呢?首先记事本是属于文本模式的,所以会将数据作为ASCII码,然后转换为对应的字符,所以在存入数据的时候必须是存放123456这几个字符对应的ASCII码;看看123456各个字符对应的ASCII码:
“1” ->49;
"2" ->50;
.......
"6" ->54;
所以在存入数据的时候,我们应该存入的是49-54几个数字,那样在存的时候我们就有不同选择了。
1、创建一个int型数组,把49-54几个数字分别赋给数组中的元素,
2、创建char型数组,直接把1-6几个字符赋给数组元素。
这样结果都是正确的。
最后总结一下,二进制文件存放的就是数据的原始形式,而文本文件存放的就是数据的ASCII码。用二进制方式存放的数据,可以用文本模式打开,相反亦然。但是,我们要避免这样做,因为就想上面所说的,当遇到10的时候,这两种模式的处理方式就不一样,所以我们应该用什么模式存放的数据就用什么模式打开。
.......
"6" ->54;
所以在存入数据的时候,我们应该存入的是49-54几个数字,那样在存的时候我们就有不同选择了。
1、创建一个int型数组,把49-54几个数字分别赋给数组中的元素,
2、创建char型数组,直接把1-6几个字符赋给数组元素。
这样结果都是正确的。
最后总结一下,二进制文件存放的就是数据的原始形式,而文本文件存放的就是数据的ASCII码。用二进制方式存放的数据,可以用文本模式打开,相反亦然。但是,我们要避免这样做,因为就想上面所说的,当遇到10的时候,这两种模式的处理方式就不一样,所以我们应该用什么模式存放的数据就用什么模式打开。
关于linux和windows的CR, LF, CR/LF 回车 换行问题
博客分类:
∙NO分类
WindowsLinuxUnixDOSOS
在文本处理中, CR, LF, CR/LF是不同操作系统上使用的换行符.
Dos和windows: 采用回车+换行CR/LF表示下一行.
UNIX/Linux : 采用换行符LF表示下一行.
MAC OS : 采用回车符CR表示下一行.
CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;
LF用符号'\n'表示, 十进制ASCII代码是10, 十六制为0x0A.
所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示, 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.
Dos和windows: 采用回车+换行CR/LF表示下一行.
UNIX/Linux : 采用换行符LF表示下一行.
MAC OS : 采用回车符CR表示下一行.
CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;
LF用符号'\n'表示, 十进制ASCII代码是10, 十六制为0x0A.
所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示, 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.
一般操作系统上的运行库会自动决定文本文件的换行格式. 如一个程序在windows上运行就生成CR/LF换行格式的文本文件,而在Linux上运行就生成LF格式换行的文本文件。
在一个平台上使用另一种换行符的文件文件可能会带来意想不到的问题, 特别是在编辑程序代码时,有时候代码在编辑器中显示正常, 但在编辑时却会因为换行符问题而出错。
很多文本/代码编辑器带有换行符转换功能, 使用这个功能可以将文本文件中的换行符在不同格式单互换。在不同平台间使用FTP软件传送文件时, 在ascii文本模式传输模式下, 一些FTP客户端程序会自动对换行格式进行转换。经过这种传输的文件字节数可能会发生变化。如果你不想ftp修改原文件, 可以使用bin模式(二进制模式)传输文本。
表一:
标志CRLF
符号 | 十进制Ascii码数 | 十六进制数 |
\r | 13 | 0x0D |
\n | 10 | 0x0A |
表二:
标志换行
Win/Dos | linux,Unix等 | |
\r\n(<CR><LF>) | \n(<LF>) | |
所以在用println函数的时候,导致的换行在不同操作系统中可能不一样,在windows下表现的是“\r\n”,使用的时候要注意。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论