变量

今天学习的内容应该算是非常基础的东东,每个语言都会用到它,越是基础的东西,越要认真学,这样往深走的时候才会走得更加踏实,当然简单的东西并非真的“简单”,所以接下来就按步就班地学习这些看似“很简单”的知识点,当然下面记录的都是平常不怎么会的细节。

常量:

对于C语言来说,常量有如下几种类型:

 

其中对于回车换行符得说明说明:

\r   回车  cariage return  简称CR,含义:光标定位到行首

\n   换行  line feed  简称LF,含义:光标移到下一行

而平常我们所说的换行是指:光标定位到行首 + 光标移到下一行 = \r + \n

在不同的平台下,回车的表示也是不同的,如下:

① Windows平台:\r\n  CRLF

② Unix平台:\n LF

③ Mac平台: \f CR

① 下面做一个实验来验证Windows平台回车的表示是否真的由\r\n两个字符组成呢?

首先新建一个文件,注意观看其大小:

 

通过EditPlus文本编辑器打开【随后需要用到它里面的功能】,里面敲一个回车换行:

这时保存,查看一下这时的大小:

可见确实是两个字符表示回车,那这两个字符是否真的是\r、\n呢?这时用EditPlus中的十六进制来查看里面的内容:

我们知道,第个字符都对应一个ASCII码值,所以,通过查询ASCII码表就知道这两个数值代表的字符是多少了,在linux中可以直接通过帮助查看到:

 

所以论证了在windows上回车是由\r\n两个字符组成。 

② 下面再到Linux(准Unix平台)下来论证回车字符是由\n组成:

同样首先新建一个文件,里面敲入一个字母a+回车

 

同样,查看文本内容中的字符,用od -c 命令:

从中可以发现,多出来一个换行符,然后是\n\n代表linux换行么?答案是VI编辑器默认会给内容加一个换行,在a前面再加上换行符就可以论证我们的观点是没错的:

再查看文本中的字符:

变量:

关于什么是变量,这个就不用多说下,这里列一下在C语言的所有保留关键字,之后会一一学到,主要是要避免变量的命名与保留关键字同名:

 下面来探讨一下C语言中变量的一些特点,及它的生存期与作用或

特点一:一个局部整形变量,如果没有初始化,它的值是不可预期的。

 

运行结果:

特点二:全局整形变量的值如未初始化,它的值为0:

 运行结果:

特点三:局部和全局静态整形变量未初始化,值也为0:

运行结果:

 实际上对于不同的变量,它在内存中的分配是不一样的,下面就来探讨一下C程序的执行环境

对于一个可执行目标文件,实际上它是ELF文件格式,它里面包含程序的很多信息,如:ELF文件头信息、程序头、代码段、数据段等,可以用

readelf:来显示ELF文件信息:
 
里面就包含很多信息,下面列一下典型的:
 
 
可见可执行文件是有一定的格式的,对于内存,实际上它也是进行分段的,如下面所示:
那C程序编译成的可执行程序分段和内存也进行分段,这有什么意义呢?
实际上可执行程序以一定的格式进行保存,目的也就是为了加载到内存的不同段中,而行代码段的数据就加载到内存的代码段中,对于数据段就加载到内存的数据段中,这时PC指针就从代码段开始执行我们写的程序,
内存分段的好处,也可以总结如下:
1、可以将程序的指令与数据进行区分
2、可以对不同的段施加不同的属性,代码段是只读的,简称r/o段;数据段是可读写的,简称r/w段,可以防止代码段中的指令被有意或无意地破坏
3、可以提高程序的可靠性,有利于缓存
4、多个进程可以共享,共享存储器中的数据或代码,可以减少内存使用
 
对于c语言从代码生成可执行文件可以分为如下几个步骤,这也是大家都熟知的:
其中要说明一下最后一步"链接器"生成可执行程序的作用:简单的说就是将多个目标文件合并在一起,主要作用是重定位。将目标文件的函数地址、变量地址重新定位。
下面对一个目标文件来进行分析:
 
 
这时,对其进行编译,生成.o目标文件:
可以用如下命令来查看其文件信息:
这时我们来查看下目标文件的汇编代码,注意,这个.o是没有进行链接过的:
而通过链接之后的可执行目标程序,则除了包含.o相关的代码,而且还会包含一些库的代码,通过如下命令可以查看到:
这时,再通过objdump来查看目标可执行文件的汇编代码,就会多了很多内容了.
对于C程序,我们知道它的入口函数是main,其实真正的入口函数不是它,通过这个目标汇编就可以看到:
 
 
 
 
说明:关于链接器的一些概念,只需了解一下,实际上一个链接器比编译器要复杂得多,主要是通过简单分析建立一个对C程序的编译执行环境有一个了解,建立一个正常的编程观念,这才是重点。

接下来,通过代码,来理解一下代码对应的各个段信息,清楚理解了哪些变量存在内存的哪个段中,对之后C语言的深入分析能打下一个比较好的基础【仔细看其过程,可能有点绕】:

分析这段程序:

可以通过如下命令来查看.o文件的总段信息:

上面的text、data、bass段,分别对应内存的分段,从上面信息可以看到,还没有数据段,只有代码段,大小为41个字节,结合程序代码来分析,看是否信息正确:

说明:text段,称为代码段,通常“常量值”也归为代码段中,因为它们都是只读的。

从代码来分析,只有13个字节的常量,跟总text段的41个字节不相符,根据上面的说明,可以查看更详细的信息,就可以明白了:

下面来进一步说明段信息:

在代码中加入数据:

从以上实验就论证了:未初始化的数据是存放在bss段中,已初始化的数据是存放在data段中,另外bss段中在生成的可执行文件中是不占用大小的,只会在运行时分配大小,而data段中的数据则会占用。

 下面要来研究全局变量(未初始化和初始化)在段中的分配情况:

未初始化

为了能说明情况,先看下目前生成的目标文件可执行文件的bss段信息,以便进行对比:

目前编译生成的目标文件的bss段信息为00000008

目前链接生成的可执行文件bss段信息的值为00000010,下面开始增加一个全局未初始化的变量:

这时查看一下目标文件的段信息:

总结:对于全局未初始化的变量,它在编译时是不会分配大小的,只有链接生成可执行文件,才会分配。

已初始化:

为了做对比,先看下目前编译生成的目标文件的data段信息:

 

 

总结:已初始化的全局变量在编译时就会分配大小。

变量的作用域

下面来看一下局部变量的作用域:

 

运行结果:

如果在之外使用它,则会报异常:

出了作用域,则分配给该变量的内存也会随之自动释放。

对于这些规则,都比较容易,下面要来说明一下静态局部变量,来说明一个问题:

它的作用域是在花括号之间,出了花括号,则就不能使用它了,但是静态局部变量的生命周期并非出了花括号就销毁了,而是当整个程序退出了才会销毁

总结:变量的作用域不一定等于生命周期。

好了,关于变量的使用人人都知道,但是对于其深层次的东西,其实在学习中也挺重要,内容有点多,需好好消化,下回见!

posted on 2013-11-17 10:37  cexo  阅读(437)  评论(0编辑  收藏  举报

导航