TCC直接执行C源文件的能力也会减轻我们的负担

TCC(TinyCC)有个特性,就是可以将C源文件像执行脚本一样直接执行,而省去了手工编译等过程。一开始我并不觉得这是一种很大的优势,因为如果编写脚本的话,Python,Perl要方便多了,尤其是处理字符串之类的。
      最近我突然发现,TCC的这一特性对于做电子相关领域的人而言还真是非常有用。比如,像我们这样的万能打杂者,经常处理由FPGA,DSP什么的导出的数据(比如《从QuartusII中导出的tbl文件中提取数据并绘制波形(续)》),这些数据可能是754标准浮点型,但是通过串口一个字节一个字节传出来的,或者是由12位补码高位补零变成32位数据传出来的,或者是以十六进制形式存储的浮点数据。对于这样的任务,C语言简直就是完美的武器,但是这样的tactical mission总是在不断变化,需要特别灵活的工具才能使计划跟上变化。所以一般都是Python+Ctypes处理。虽然ctypes是很强大的操作C数据类型的工具,但是比起直接用C,还是稍微有点麻烦。
      如果把gawk的管道能力和TCC直接执行C源文件的能力结合起来,则可以得到一种灵活而强大的数据处理工具。举一个例子,比如有下面一个数据文件:
    3f800000
    40000000
    40400000
    40800000
    40a00000
    40c00000
    40e00000
    41000000
其中第二列数据是以十六进制方式存储的754标准32位浮点数,现在想将第一列为奇数的所有行的第二列转换成浮点数的形式。首先用C写一段代码,将从stdin读入的十六进制数据转换成浮点形式,并从stdout输出:
#!/usr/local/bin/tcc -run
#include <stdio.h>

// 2011.05.21 PM 09:46
// x2f.c
// xialulee

int main() {
  int x;
  while (scanf("%x"&x) != EOF) {
    printf("%f\n"*((float*)&x));
    fflush(stdout);    
  }
  return 0;
}

接着,写gawk代码:
xialulee@xialulee-pc3 /c/lab
$ gawk '
BEGIN {
  x2f = "x2f.c"
}
($1 % 2) {
  print $2 |& x2f
  x2f |& getline
  print $0
}
END {
  close(x2f)
}' data.txt
1.000000
3.000000
5.000000
7.000000

从上面的输出中,可以看出我们的目的达到了。之前为了处理这类事情,还煞有介事的写了个C程序,见《转换浮点数和字节串的控制台程序》。想一想还真是麻烦。以前还利用awk的算术运算实现了类似的功能,见《用awk将"unsigned decimal"reinterpret成"float"(续)——使用程序文件》。
      再举一个例子,还是12位补码的问题,以前讨论过无数次(参见《AD补码数据和位段结构体(再续)——用weave嵌入C代码》)。AD采集的12位有符号数,高位补零之后变成了32位数据,比如0x00000ffe,对应的数值是-12。用于数据转换用C代码:
#!/usr/local/bin/tcc -run
#include <stdio.h>

// 2011.05.21 PM 09:54
// ad12.c
// xialulee

int main() {
  int x;
  while (scanf("%x"&x) != EOF) {
    printf("%d\n"x<<20>>20);
    fflush(stdout);
  }
}

假如数据文件内容为:
ff0
ff1
ff2
ff3
ff4
ff5
ff6
ff7
执行gawk代码:
xialulee@xialulee-pc3 /c/lab
$ gawk '
> BEGIN {
  ad12 = "ad12.c"
> }
> {
  print $1 |& ad12
  ad12 |& getline
  print $0
> }
> END {
  close(ad12)
> }' data.txt
-16
-15
-14
-13
-12
-11
-10
-9

      上面的这些例子中,我们将gawk操作文本数据的能力和C操作底层数据类型的能力结合起来,把问题解决了,而且直接用tcc执行了C的源文件,而不用人工编译C程序。虽然对付上面这些简单的例子而言似乎也并没有便利多少,但是对于我们这样作为万能打杂者的特殊单位而言,灵活性常常是第一位的,尤其是对于多变的tactical mission中应用的,经常需要修改的小段C代码。当任务变得复杂而繁重时,即使一点小小的便利也能带来巨大的实惠。

附一:fflush(stdout)
      如果想要C程序能够被别的程序调用,并通过stdin和stdout作为数据传输的通道,一定不要忘了在printf之后fflush(stdout)。如果不这样做,那么另一端的程序就卡住了。对于利用了C的IO库的其它语言而言,也存在同样的问题,更多细节可以参看PP3E,哪一页记不住了。

附二:Windows下用tcc
      TCC同样可以在Windows下方便运行,上面的例子其实都是在Windows中做的,借助msys,和Linux下的操作没有区别。在msys的bash中用df命令查看/usr对应哪个目录,然后将tcc的可执行文件们放到/usr/local/bin中(没有就自己建立),"include"和"lib"目录放到/usr/local中,就可以了。

附三:Windows下用gawk
      如果想利用gawk的管道功能将awk的文本数据处理能力和C的数据操作能力结合起来,不要用GnuWin32的gawk,因为它不支持|&运算符。msys的gawk可以。

附四:x<<20>>20?
      这是什么意思?我的朋友们常常用if else这种方式判断12位补码的符号位,再根据符号位的值处理高于12位的所有位。我之前在一直用位段union这种方式来处理。其实x<<20>>20不是更简单一些吗?其实位段union处理12位补码的方法在底层也是这样实现的,我通过查看反汇编代码发现的。C中的>>运算符是逻辑右移还是算术右移呢?这和操作数的类型有关,如果被移位的变量为有符号类型,则是算术右移。先通过左移,将12位补码数据的符号位顶到32位数据单元的最高位,再用算术右移拉回来,就处理好了!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值