深入研究C语言 第一篇
一. 研究过程
1.第一章:创建编译环境:
我们首先下载TC2.0,找到其中与编译连接相关的程序和文件:
(1) 编译器:TCC.exe
(2) 连接器:tllike.exe
(3) 相关文件:c0s.obj、cs.lib、emu.lib、maths.lib
将文件放在C:\C目录下。
编写程序测试我们的编译环境:
在这里我们看到,程序被正常的编译。生成了.exe文件。并且可以正确执行。
当然,在TC中,c0s.obj、cs.lib、emu.lib、maths.lib这四个文件时在TC目录下的lib文件夹下,但是我们如果将lib文件夹直接放入C:\C目录下,程序在编译的时候会提示:
C0s.obj:Unable to open file
这是因为,TCC没有找到lib目录下的c0s.obj文件,我们可以推知,TCC默认在寻找文件的时候只在自己同层的目录下寻找。
在这里我们发现,我们只用了TCC,并没有用到TLINK。那TLINK的作用是什么呢?
我们删除TLINK。然后进行编译连接的工作。我们看到:
我们看到,TLINK其实是被TCC调用实现功能的。
书中的解释是:TCC.EXE 将a.c编译成a.obj
TCC调用TLINK将c0s.obj、cs.lib、emu.lib、maths.lib中的相关代码连接到一起生成.exe文件。
在刚才的步骤中,虽然我们没有生成.exe,但是我们发现,生成了1.obj。那么,我们把TLINK重新找回来,能不能将这个1.obj连接成.exe呢?
我们尝试:
我们发现我们成功的连接完成。
当我们用TCC编译时,程序可有两个最大为64K的段,一个段为代码段,栈和数据段共用一个段。我们如何来验证这一点呢?(注:这里其实是用到了后面的内容)。我们编写这样一个程序,让其显示程序运行时CS和SS,DS的值。
我们编译运行,查看结果:
我们发现,CS是一个值,DS,SS两者值相等。这样也就验证了代码段为一个段,栈和数据段共用一个段。而我们又知道,每个段地址不变,偏移地址从0000-ffff是64K的字节。所以这两个段的最大值是64K。
另外,我们在CMD中直接输入TCC,会显示出TCC的使用参数,如下:
2.第二章:显示函数的段地址和偏移地址:
我们继续研究第二章的内容:
在main函数中添加语句,使下面的程序可以打印出所有函数的段地址和偏移地址。
程序如下:
我们最直接的想法是用取地址的方式来查看。我们知道,在C语言中,&的作用是取地址。比如:
运行后结果如下:
那么,函数是不是也可以这样来取地址呢?我们尝试:
在这里,我们直接加类似&f1这样的取地址加函数名的形式可以么?我们分析:在debug中,我们看到子程序调用是都是执行的CALL(地址)的方式。在这里,函数名和标号有着类似的作用,就是方便编程人员编程、方便编译器编译和链接。他的本质应该是一个地址值。
我们直接编译看看是否会报错,证实我们的猜想。
我们发现没有报错。也就说明这里的函数名确实被翻译标号或与标号类似的东西。
为了方便查看,我们让这些地址以16进制的方式显示出来。结果如下:
那么我们所找到的值是不是函数的入口地址呢?我们进入debug查看:
我们看到,在01fa中,是我们定义的F1函数中的语句,int a=1;也就是说我们的想法是正确的,在printf中直接取函数的地址输出是可以的。
但是,我们看到,我们打印出的是函数的偏移地址,段地址如何打印呢?
我们知道,在C语言中,我们可以直接调用一些汇编的寄存器,而在汇编中,CS寄存器记录的是程序段的段地址,也就是说,我们只要显示出CS,就可以显示出程序段的段地址。
我们编写:
运行后其结果如下:
但是这个结果对不对呢?我们还得从debug中验证:
我们看到,在Debug中-g运行后的结果与CS的值相同。都是0b3b。这也就说明了程序所显示就是程序在执行时的程序段地址。
那么这两次执行2.exe所显示的程序段地址为什么会不同呢?我们知道,第一次我们是直接在cmd中运行的2.exe,程序接受系统调用自己执行。而第二次我们是用debug加载进入系统,然后执行。在debug加载的时候,程序被debug加载到了指定的程序段位置。
二. 附加研究:
在进行研究时,我发现在C语言显示变量的偏移地址时,不同的变量显示的地址值是不相同的。
比如,全局变量显示如下:
局部变量显示如下:
这个结果让我疑惑,但是我想起了局部变量和全局变量的区别,又看到了-32这样的值,我猜想这应该是局部变量记载的是相对位置而不是绝对位置。因为绝对位置不会出现负数。我编写程序如下:
在debug中,我-g到第二个printf();函数前,也就是显示出变量a的地址后。
通过当前的SS:SP的值与-28进行计算,查看结果单元,发现:
这个单元内所存放的数就是变量a的值,也就是说这个单元就是变量a的存储单元。
所以得出结论:在C语言中,全局变量的地址是记录其存储单元的偏移地址,而局部变量的地址是记录其存储单元与现在栈顶指针的相对位置。
(注解,重要:在这里后期我在回头看的时候,发现这里使用的是%d方式,这很重要。因为地址是FFE4,这是一个十六进制的数,本应该用%f的方式显示出来。而正是两种数不同的表达和显示方式造成了这样的现象。而非是上面的结论。这里为了过程的完整而保留了这个问题。在此改正。)
深入研究C语言 第一篇的更多相关文章
- 深入研究C语言 第一篇(续)
没有读过第一篇的读者,可以点击这里,阅读深入研究C语言的第一篇. 问题一:如何打印变量的地址? 我们用取地址符&,可以取到变量的偏移地址,用DS可以取到变量的段地址. 1.全局变量: 我们看到 ...
- 深入研究C语言 第二篇
1. 程序一: 首先我们研究如下程序: 回答如下问题: 1. 程序运行时n,a,b,c的段地址在哪个寄存器中? 全局变量的存储空间在什么段里?局部变量的存储空间在什么段了?参数在什么段里?函数的返回值 ...
- 深入研究C语言 第二篇(续)
1. 关于如下的程序,关于结构体的拷贝,拷贝是拷贝到内存中的什么地方? 我们进入debug进行反汇编,单步等操作跟踪查看.发现: 在main中,我们看到call 0266应该对应的是转跳到func处执 ...
- C语言第一篇博客
你对网络专业或者计算机专业了解是怎样? 进行网络安全,防止信息泄露. 你了解C语言么?C语言主要应用有哪些? C语言简言之就是一门计算机的编程语言. C语言主要应用于应用软件,服务器端开发,系统软件和 ...
- Scala语言笔记 - 第一篇
目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 最近研究了下scala ...
- 如何起草你的第一篇科研论文——应该做&避免做
如何起草你的第一篇科研论文——应该做&避免做 导语:1.本文是由Angel Borja博士所写.本文的原文链接在这里.感谢励德爱思唯尔科技的转载,和刘成林老师的转发.2.由于我第二次翻译,囿于 ...
- [老老实实学WCF] 第一篇 Hello WCF
老老实实学WCF 第一篇 Hello WCF WCF(Windows Communication Foundation)是微软公司推出的面向服务技术的集大成者,涵盖继承了其之前发布的所有的分布式应用 ...
- 老老实实学WCF[第一篇] Hell wcf
老老实实学WCF 第一篇 Hello WCF WCF(Windows Communication Foundation)是微软公司推出的面向服务技术的集大成者,涵盖继承了其之前发布的所有的分布式应用 ...
- (转)[老老实实学WCF] 第一篇 Hello WCF
http://blog.csdn.net/songyefei/article/details/7363296#comments 老老实实学WCF 第一篇 Hello WCF WCF(Windows ...
随机推荐
- faster-rcnn(testing): ubuntu14.04+caffe+cuda7.5+cudnn5.1.3+opencv3.0+matlabR2014a环境搭建记录
python版本的faster-rcnn见我的另一篇博客: py-faster-rcnn(running the demo): ubuntu14.04+caffe+cuda7.5+cudnn5.1.3 ...
- avalon2.2.3发布
avalon2.2.3这次发布带许多好的东西 首先正式有了自己的LOGO 其次有了自己的QuickStart 样例工程, 这个工程整合了路由,表单,表格,切换卡等组件 https://github.c ...
- spark配置lzo
spark1.0版本 spark-env.sh中 export SPARK_LIBRARY_PATH=$SPARK_LIBRARY_PATH:/soft/hadoop/lzo/lib/export S ...
- python学习心得第二章
python基础 1.关于python编码的问题. python的编码现在主要是两种版本python2.7和python3.5 python2.7默认的是ascii码进行编译,我们可以采用 # -*- ...
- linux 学习3 第四讲 文件常用命令
好几天没有在网上总结了.我把ppt先誊写在本子上,这样听的时候记录就方便很多,添些东西就可以. 我想先看shell那部分,但是没有之前几章的准备,是没法跟着视频动手操作的.所以还是按部就班得学习. 虽 ...
- C# 自定义特性
http://www.cnblogs.com/tekkaman/p/3983360.html#undefined https://msdn.microsoft.com/zh-cn/library/sw ...
- netty发送utf-8编码的信息
/** * */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // (1) // ...
- git ssh端口号变更之后所需要的修改
假设原本的repository地址为:git@gitlab.cjx.com:jinxin/project2.git 端口变更之后,需要调整为:ssh://git@gitlab.cjx.com:PORT ...
- python之路-Day4
本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 函数是什么? 函数一词来源于数学,但编程中的「 ...
- range()和xrange()区别
版本:Python2.7 1.先看帮助说明 (1)range()返回一个递增或递减的数字列表,列表的元素由三个参数决定 start 表示列表开始的值,默认为0 stop 表示列 ...