本篇研究TC2.0下其他几个工具。同时看看TC由源代码到exe程序的过程。

1. 用TCC将下面的程序编为.obj文件

我们知道,TCC在默认的编译连接一个C语言的源程序a.c的时候分为以下两步:

(1).TCC将源程序文件编译成a.obj。

(2).TCC调用TLINK将c0s.obj,cs.lib,emu.lib,maths.lib中的a.obj中的程序要用到的代码与a.obj的代连接到一起生成.exe文件。

并且,我们还知道,TCC可选参数有如下:

我们看到有这样的选项:Compile only(只编译)。这应该是只编译生成.obj文件的选项。我们验证如下:

我们看到,文件夹下确实只生成了.obj文件:

2.用C:\C\tcc a.c的方法编译下面程序:

我们看源程序,很明显的没有定义和实现f函数。我们看编译连接过程中的错误提示:

如我们所料,这里出现了错误提示:在a.c中没有发现f函数。

我们看错误提示,在a.c中没有发现f函数。我们很容易想到,这里是不是不止从a.c中寻找f函数?或者这里是不是可以不止从a.c中寻找?我们又联想到TCC函数有同时编译连接多个.c文件的选项。我们尝试编写两个文件,并共同编译:

编译连接过程:

我们看到并没有错误提示。并且在文件夹下生成了A.exe。我们运行查看:

我们看到,将同一个程序写在两个文件中,程序也可以正常的编译连接。

3.TLIB.exe

我们从书中看到,TC2.0给我们提供了一个工具tlib.exe,可以用tlib.exe将一个.obj文件中的代码加到一个.lib文件中。

首先我们需要了解TLIB.exe的参数。我们仿照TCC的方法,在cmd中执行TLIB。其参数表如下:

我们看到其参数,+是将一个文件添加进lib文件中。我们尝试:

我们看其属性,他确实被修改了。

然后我们尝试再次编译a.c。发现没有了错误提示:

我们加载进debug,找到程序的main函数和f函数的代码:

我们看到main函数中只有一句调用的call指令,根据我们代码的对比,我们知道这里调用的就是f函数。我们查看f函数的代码:

我们运行:发现其实a.c调用的f()函数就是4_1.c中的f函数。

回顾我们整个过程,我们可以得出这样的结论,虽然我们没有写函数f,但是a.exe中函数f的代码在连接的过程中从cs.lib中得到。

4.将下面的程序编译为f.obj,将f.obj加入c:\c\cs.lib。

程序f.c如下:

下面的程序编译连接为b.exe。

我们编译完成后进入debug查看。主函数中代码如下:

看到,在函数调用的部分,都采用了call的方式,并且call的位置离主函数的比较远。也就是说,call部分的函数没有和main连续。我们转跳到其调用的部分。查看其代码。

我们对应f.c查看,我们可以看到,其实这三个子程序就是f1,f2,f3函数实现的语句。并且,虽然在b中没有调用f3,f3的代码也在b中。

很明显,经过修改cs.lib,我们的程序可以调用f1,f2,这就说明了,b.exe中的代码是在连接的时候从cs.lib中加入的。

那么,是因为这三个函数在同一个文件中被加入cs.lib中,所以才出现这样同时都被加载进入的结果么?

我们把f3单独拿出来,加入cs.lib(在此过程中,把cs.lib还原成tc2.0自带的cs.lib)

这时我们在编译连接b.c,然后进入debug加载:

我们看到,这里没有了f3。那么是不是被放在了其他地方呢?我们看看调用f3的时候它应该再什么地方。

我们修改一下b.c,使他调用一下f3。

进入debug加载查看。

我们看到,f3实现的子函数就在f1,f2的后面。也就是有如下事实:如果f3被调用,那么他的地址就是在f2后面。如果f2后面没有f3,也就是f3没有被调用。这样,就否定了f3在被放在了其他地方的推论。也进而说明了,分别编译,分别加入cs.lib这个方案是可以实现用到哪个函数,装入哪个函数的代码的。

5.替换printf

用TLIB.EXE将cs.lib中的printf函数代码变为下面程序的代码:

通过前面的几个程序我们知道,cs.lib中也有printf函数对应的代码。那么我们就不能像前面的几个程序那样添加.obj进入cs.lib中了。而应该是替换。我们看TLIB.EXE的参数表,发现-+是替换的。我们尝试:

发现无错误提示。我们编写一个程序如下,测试printf是否被替换成功:

编译连接后执行:

这里证实,printf确实被替换成了我们自己编写的printf。

6.思考:

TCC这样做有什么好处呢?首先我们知道,在cs.lib中包含常用的一部分函数,可以使得TCC在编译基本功能的程序时,不需要在包含头文件。其次,我们知道,一般情况下,同一个文件中的函数之间一般是相互关联的。有些是相互调用实现一个共同的功能,有些是实现不同的功能但是是对同一类数据操作的。这些函数写在同一个文件中,包含的时候同时包含进去,这样就减少了由于没有包含而出现错误的情况。另外,可以自定义的替换其中的函数,保证了程序的多样性和能够方便的修改的特性。

深入研究C语言 第三篇的更多相关文章

  1. 深入研究C语言 第四篇

    这里更多探究的是指针的机制. 用debug对下面程序进行分析,记录每一条C语句运行后,相关内存单元的值. 程序a.c 注意理解指针机制 我们编写如下代码: 编译加载进debug查看: 我们先看其反汇编 ...

  2. 深入研究C语言 第一篇(续)

    没有读过第一篇的读者,可以点击这里,阅读深入研究C语言的第一篇. 问题一:如何打印变量的地址? 我们用取地址符&,可以取到变量的偏移地址,用DS可以取到变量的段地址. 1.全局变量: 我们看到 ...

  3. Scala语言笔记 - 第三篇(容器方法篇)

    Scala语言笔记 - 第三篇(容器方法篇) 目录 Scala语言笔记 - 第三篇(容器方法篇) map和flapMap方法: ​ 最近研究了下scala语言,这个语言最强大的就是它强大的函数式编程( ...

  4. PHP 性能分析第三篇: 性能调优实战

    注意:本文是我们的 PHP 性能分析系列的第三篇,点此阅读 PHP 性能分析第一篇: XHProf & XHGui 介绍 ,或  PHP 性能分析第二篇: 深入研究 XHGui. 在本系列的 ...

  5. Scala语言笔记 - 第一篇

    目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 ​ 最近研究了下scala ...

  6. 我的屌丝giser成长记-研三篇

    进入研三以来,基本都是自己的自由时间了,从导师的项目抽离出来,慢慢的都交给师弟他们来负责.研三的核心任务就是找工作以及写毕业论文,因为有导师科研基金项目成果作为支撑,所以自己的论文没什么可担心,一切都 ...

  7. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

  8. 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装

    微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...

  9. 第三篇 SQL Server安全主体和安全对象

    本篇文章是SQL Server安全系列的第三篇,详细内容请参考原文. 一般来说,你通过给主体分配对象的权限来实现SQL Server上的用户与对象的安全.在这一系列,你会学习在SQL Server实例 ...

随机推荐

  1. C# iis错误配置信息( 500.21 - Internal Server Error )

    新电脑安装完开发环境后,还需要注册framework4.0到IIS.不然会报错: HTTP 错误 500.21 - Internal Server Error 处理程序"Extensionl ...

  2. Entity Framework技术导游系列 开篇 (转)

    在微软平台写程序有年头了,随着微软数据存取技术的持续演化,我在程序中先后使用过ODBC.DAO.ADO.ADO.NET.LINQ to SQL. Entity Framework这些技术. 近几年来, ...

  3. python学习心得第五章

    python学习心得第五章 1.冒泡排序: 冒泡是一种基础的算法,通过这算法可以将一堆值进行有效的排列,可以是从大到小,可以从小到大,条件是任意给出的. 冒泡的原理: 将需要比较的数(n个)有序的两个 ...

  4. SQL ROW_NUMBER()实现取组内最新(最大)的数据

    SELECT * FROM(select ROW_NUMBER() over(partition BY sid order by cscore desc) as tid,sid,cname,cscor ...

  5. laravel框架学习

    在聊技术之前,我们首先谈谈研究生的生活现状.进入到研究生忙碌的生活中,研究生是这么一个群体,外界对研究生的爱称是"研究僧",为什么我自己会觉得会是爱称.因为研究僧说的是研究生对自己 ...

  6. 使用Linux碎解一

    一.安装VMwarestation. 二.安装Linux系统(这里是CentOS7) 步骤: #==========================part1===================== ...

  7. 玩转UICollectionViewLayout

    前言: 实 现垂直方向的单列表来说,使用UITableView足以:若是需要构建横向滑动列表.gridView等直线型布局,则使用 UICollectionView+UICollectionViewF ...

  8. python项目实践一:即时标记

    转自:http://www.code123.cc/1317.html 这是<python基础教程>后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python ...

  9. NIO vs. BIO

    性能测试 BIO -- Blocking IO 即阻塞式IO NIO -- Non-Blocking IO, 即非阻塞式IO或异步IO 性能 -- 所谓的性能是指服务器响应客户端的能力,对于服务器我们 ...

  10. postgres 批量更新内容

    在程序中遇到这样的需求, 数据库表格式如下 需要把批量更新status, 如name = fox 时, status = 1, name = boa 时,status = 2 .... 类似的 pos ...