实现一个基于tcc/tlink的简单的编译链接工具

实现一个基于tcc/tlink的简单的编译链接工具

一、基础研究

在这里我们需要提供一套新的c语言开发工具cc,它支持的c程序不是从main开始运行而是从CMain开始运行。

书上已经对该工具程序进行了需求分析:(1)要在屏幕中间显示彩色的字符串;(2)等待用户输入,按下任意键后开始运行程序员写的程序。

也给出了由需求分析进行的功能分析:代码文件main.obj实现打印字符串、等待输入、调用程序的功能。编译链接文件cc.exe实现调用tcc编译文件、调用tlink连接文件的功能。

新建文件夹,在其中实现main.c如图:

 实现一个基于tcc/tlink的简单的编译链接工具

main.c编译成main.obj文件,并将tcc.exetlink.exe以及编译连接所需文件都拷贝到文件夹中。

这里我们要实现一个编译连接程序cc.cc.bat功能相同。

那么首先来看看什么是批处理文件:批处理就是对某对象进行批量的处理。批处理文件的扩展名为.bat。在“命令提示”下键入批处理文件的名称,或者双击该批处理文件,系统就会调用Cmd.exe运行该批处理程序。我们来看看c.bat的内容:

 实现一个基于tcc/tlink的简单的编译链接工具

这里@表示不显示@后面的命令,echo是一条批处理指令,echo off是关闭回显功能,即后面的语句执行时都不会在屏幕上显示。%1表示传过来的参数。

但是这里批处理使用了dos命令tcc和tlink,而dos命令是不能直接写在c程序里的,能否在c程序里使用dos命令呢?我们来看system函数的功能,它可以发出一个dos命令,如我们要在c程序里使用命令tcc main,可以用system(“tcc main”);来实现。这里还要用到的一个函数strcat,可以把一个字符串添加到另一个字符串结尾处,覆盖另一个字符串结尾处的‘\0’)并添加‘\0’,合成一个完整的字符串。

一个参考程序putarg.c,我们来看看它的内容:

 实现一个基于tcc/tlink的简单的编译链接工具

这个程序的作用是将arg字符数组的值作为一个字符串输出,而且我们要注意这里的参数arg是一个二阶指针,它的作用是什么呢?我们来运行一下:

 实现一个基于tcc/tlink的简单的编译链接工具

 

首先输出了当前的绝对路径,然后输出了我们加在后面的参数,这说明程序是将命令行的参数名作为字符串即字符数组的形式来处理的,*arg的值为参数的字符串的首地址,而**arg的值是字符串的每一个字符。为什么这里n代表命令行参数的个数,arg指向参数的首地址呢?查找资料可知这是main函数不是作为普通函数来使用的,所以它的参数是有特殊用途的。main函数如果带参有两个参数,那么第一个表示参数的个数;第二个参数中argv[0]为自身运行目录路径和程序名,argv[1]指向第一个参数、argv[2]指向第二个参数、等等。

那么我们就可以通过使用带参数的main函数接收我们要编译连接的c文件名,然后将它用strcat进行处理,在用system执行进行编译连接。

编写程序如下:

 实现一个基于tcc/tlink的简单的编译链接工具

这里用数组abcd存储批处理文件里不用改的部分字符串。在开始进行判断,如果n小于2,说明在命令行没有输入要编译的文件名,则提示错误信息并返回。

之后将要编译的文件名加在数组a的后面,形成一句完整的tcc编译语句,将目标文件编译成obj文件。因为arg指针指向的第一个值是本程序的绝对路径,即arg[0]的值是本程序的绝对路径,而arg[1]是存储要编译的文件的字符串的首地址。然后用system执行数组a存放的tcc编译语句。

之后要判断字符串是否结束,如果未结束,则判断字符是否为’.’,因为我们如果在命令行输入的参数是XXX.c,那么tcc时后面加XXX.c是正确的,但是在tlink语句里面加XXX.c是错误的,应该用XXX或者XXX.obj,为了简便我们就使用名字。然后将“.”改成转义字符“\0”表示字符串已经结束。

之后再用strcattlink连接语句拼接好用system执行。

执行结果如下:

 实现一个基于tcc/tlink的简单的编译链接工具

如果不输入文件名则提示错误。如果输入则正确编译连接。运行编译连接生成的exe文件如图:

 实现一个基于tcc/tlink的简单的编译链接工具

 

先在屏幕中间显示显示彩色字符串,再执行CMain函数“welcome to c”,输出字符串“hello world!”。

二、扩展研究

(1)为什么main函数的参数是参数的个数和命令行参数字符串?

答:我认为是参数是在程序跳转到main函数之前初始化时将命令行的参数的字符串地址传递到栈里,再在main函数里通过栈调用。

三、研究总结

今天我们自己基于tcctlink实现了一个编译连接工具cc,它的功能与tcc相似,都是编译连接程序,只是多出了显示欢迎字符串和等待输入再执行程序的功能。向下看,其本质还是tcc的功能,我们并没有真正地实现一个编译器和连接器,向上看,这个程序的实现是一个不断集成的过程,再加上别的功能的obj文件可以组合成更大更丰富的程序。

这一章对共性和个性的分离和封装更加清晰了:共性被封装在编译工具里,个性由要编译的程序实现,按照这个思路,我们可以开发出功能更强大的编译连接工具。

这一张我觉得学习了一个很重要的函数system,我们可以通过程序来调用操作系统的功能,它与我们传统的思维是不同的,我觉得操作系统打开软件执行,软件实现功能后返回操作系统,而这里软件可以调用操作系统的功能,这使我们写的程序可以实现更强大的功能。这种操作是由顶层向底层的调用。

转载于:https://www.cnblogs.com/stormpeach/p/4364007.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/109507.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ue4 插件开发(ue4性能优化)

    UE4插件研发UE4插件扫盲UE4插件是什么UE4插件的作用UE4引擎、项目、插件的区别引擎自带的插件浏览器插件目录结构插件配置文件说明UE4插件的创建方法插件代码的执行过程四种常用模式的插件模板第三方库的引入牛刀小试创建Actor到视图插件插件发布常见的问题插件项目案例UE4插件扫盲UE4插件是什么UE4引擎和UE4项目是由各个模块组成的,其主要编程语言是C++。插件也是一个模块,说到插…

    2022年4月14日
    194
  • hdu 1286 (欧拉函数)

    hdu 1286 (欧拉函数)

    2021年8月11日
    61
  • javascript undefined_setvalidator

    javascript undefined_setvalidator解决DvaJS在models中的effects无法setInterval和setTimout的问题

    2022年9月1日
    1
  • 《QTreeView+QAbstractItemModel自定义模型》:系列教程之三[通俗易懂]

    《QTreeView+QAbstractItemModel自定义模型》:系列教程之三[通俗易懂]1、了解常用的model类通过对上一节的阅读,我们知道只要具备model+view就可以显示数据。那么有哪些model类呢,从下图中我们可以看到Qt中模型类的层次结构QStandardItemModel:可以作为QListView、QTableView、QTreeView的标准model。QAbstractListModel:需要使用QListView显示数据,并配合自定义…

    2022年6月14日
    63
  • redis分布式锁的实现(setNx命令和Lua脚本)

    redis分布式锁的实现(setNx命令和Lua脚本)前言本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结分布式锁概览在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问,Java中我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的方式。但是现在公司都是流行分布式架构,在分布式环境下,如何保证不同节点的线程同步执行呢?实际上,对于分布式场景,我们可以使用分布式锁,它是控制分布式系统之间互斥访问共享资源的一种方式。比如说

    2022年5月20日
    162
  • 位运算符有哪些_或运算和异或运算

    位运算符有哪些_或运算和异或运算位运算符的计算主要用在二进制中。实际开发中也经常会遇到需要用到这些运算符的时候,同时这些运算符也被作为基础的面试笔试题。所以了解这些运算符对程序员来说是十分必要的。于此,记录下我所理解的运算符:如果以开关开灯论:有这样两个开关,0为开关关闭,1为开关打开。与(&)运算与运算进行的是这样的算法:0&0=0,0&1=0,1&0=0,1&1=1在与运算中两个开关是

    2022年10月10日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号