Profiel van 猪哥猪哥的BlogWeblogLijstenGastenboek Extra Help

Weblog


    4-8-2009

    Droid Sans Mono with Slashed Zero

    我有收藏各种等宽字体的嗜好,尤其稀饭Sans类等宽字体。不过看到有的等宽字体的0居然不带点或者斜杠就牙痒痒,非得改之而后快。

    这个Android的Droid Sans Mono字体居然也有如此低级错误,0和O不分。所以俺就自己动手给它的0加上了一条华丽的斜杠,效果如下:
    sshot-2
    带了斜杠以后看上去就舒服多了。btw:我喜欢带斜杠的0(Slashed Zero),不喜欢带点的。做带点的0多半原因是因为简单,只要在中间瞎涂一个黑点就敷衍过去了。计划把我系统里所有0带点的Sans Mono类字体都搞成Slashed Zero(# ̄▽ ̄#)。

    下载:Droid Sans Mono with Slashed Zero
    17-7-2009

    YaTFTPSvr 1.0正式版发布

    YaTFTPSvr 1.0正式版发布,自从上次预告以来没有再增加别的新功能。再次强调:这个工具仅仅面向社会上一小撮嵌入式或底层软件开发人员,广大不明真相的群众请无视之~~

    原本想做个气势磅礴的大盒子图片来配合本次发行,不过到后来也还是一直忙得焦头烂额没时间做了。所以这次就素颜裸发了,除了文字以外什么也没有,囧rz。反正对这个东西感兴趣的也一定关注过我以前关于这东西的文章了,该知道的应该也都知道了吧俺就不废话了。以后有空会像那个BinCalc那样给它立个转正后的专门页面,不过现在还是没时间折腾~~

    暂时可以从这里下载(盒子里也有):http://zhaojie.ding.googlepages.com/TFTPSvr.zip
    12-7-2009

    YaTFTPSvr将增加流量统计功能

    自从改用搜狗拼音以来,发现没事看看累计数据感觉很爽。比如看到今天用输入法敲了5k字,一种莫名的成就感油然而生(# ̄▽ ̄#)。虽然这5k字里面分不清那些是正经的那些是灌水的~~所以我决定在我的YaTFTPSvr里面也添加传输统计功能,看看到底在开发过程中往板子上灌了多少东西进去:
    sshot-13
    累计数据也是保存在ini文件里面,每次退出的时候更新。
    8-7-2009

    YaTFTPSvr新版预告

    这个版本俺做出来有点久了。不过直到上周才最后搞定我始终很懒得搞的一个功能:窗体可变大小。因为重新计算和定位控件布局实在是一个很讨厌的体力活。搞定这个功能后准备给它转正,版本号变成1.0。这个版本功能基本冻结,原则上不再增加其他功能。

    主要的改进为:

    支持创建更多的根目录标签:不再限制于区区8个。可以点击最后的“>>”增加新的Root Tab:
    sshot-2
    由于引入了功能1,所以还需要功能2:支持删除根目录标签~~
    sshot-1
    最后就是支持窗体可变大小,方便看Log或者编辑Virtual Folder文件列表。
    9-6-2009

    拼音加加皮肤增强外挂AlphaJJ更新

    话说微软大爷最近生Bing,搞得我的Blog也被波及被伟大的网络人间奇迹GFW给ban了几天。经历了上次的Blog被Flickr封杀的事件后弄得俺是疑神疑鬼以为是不是俺的Blog又摸到了哪个大爷的逆鳞给ban了。不过后来发现所有人的Live Space都上不去以后俺才长吁一口气,等着MS做公关了。虽然MS做搜索比不过谷歌,但是公关却比谷歌强的多。谷歌的Blogger之类服务一被封杀就永无出头之日了,MS的却通常能在一周内解封。所以虽然MS Live Space有诸多不爽和恶心之处,我还是觉得抱着MS的水桶腰要比搂着谷歌的小蛮腰来的牢靠点。不过MS这几年做搜索还真是有耐心,跟东莞的那些山寨MP3厂似的一个品牌做烂了就换个马甲重新来。只不过从MS一贯的表现来看,每推出一次搜索服务,只不过多证明一次MS没有做好搜索的能力罢了。

    上周末把我的拼音加加输入法的皮肤增强外挂:AlphaJJ给改进了。这回能支持如下两种效果(不能同时使用):

    1. 输入栏半透明效果
    sshot-1
    2. 不规则输入栏效果
    sshot-4
    拼音加加这种老牌输入法皮肤不支持不规则不支持半透明真是令人发指啊,可能在所有的主流拼音输入法当中就属拼音加加的皮肤功能最差了。加了俺丑陋的小外挂后,看上去就好了点(不过我还是在用搜狗拼音,目前还没有换回拼音加加的念头)。
    sshot-3
    东西在我的盒子里下载,Patches目录下。
    21-2-2009

    猪哥的无敌TFTP Server:YaTFTPSvr发布

    终于正式把名字给改掉了,正式改为YaTFTPSvr(Yet Another TFTP Server)。注意:除非你是做嵌入式或者底层开发,需要TFTP Server来往板子上下装Bootloader或者Firmware什么的。其余闲杂人等请无视这个小玩意。因为我这个东西的开发目的就是为了方便在调试的时候通过host端往target上下装程序,不面向网管维护等应用。

    主要功能:
    • 支持无需任何配置的即开即用,满足你最简单的那种文件下载需求。
    • 支持Virtual Folder功能,如果你经常苦命要频繁切换TFTP Server Root的话,这个功能可以拯救你(# ̄▽ ̄#)。
    • 8个Root书签,每个书签位可以保存一个Real Folder和一套Virtual Folder设置。书签切换后立即对下次传输生效。
    • Real Folder的地址栏带历史自动完成,最多保存20个历史记录。
    • 彩色Log显示,凸显失败的传输。
    • 支持最小化到系统托盘,气泡提醒失败的传输。
    • 支持文件拖拽操作:可以接受从资源管理器拖来的文件并添加到Virtual Folder列表或者是更改根目录为文件所在目录。
    • TFTP协议支持Option Extension和Blocksize Option。块大小协商支持8~65464,可以传输超过32MB的文件(前提是TFTP Client要也支持以上扩展)。
    • 支持多线程并发传输。
    其他的东西都不用多说,只要是用过TFTP Server的人都懂得用的。这里只介绍本次0.2新增功能。

    Virtual Folder:

    这个功能加入的最主要理由是解决调试分布式设备时编译出来的Firmware散在不同的路径下,整机下装时需要频繁切换TFTP Server root的痛苦。最早我的0.1版本支持的Folder Tab书签其实就是为了要解决这个问题,但是解决的不够彻底(不过那时候我觉得每次能仅仅切换一下Tab就能更换root已经很爽了,可能现在用得要求又高了吧)。这回的Virtual Folder应该是可以把它彻底解决了。我自己用这个功能调试了一个多星期的内核,下装时明显安逸很多。

    Virtual Folder的功能实际上很简单,就是可以把分散在不同路径下的文件拖到一个虚拟文件夹下,这样从TFTP Client端看来好像都在同一个root目录内可以直接下载。

    如下启用Virtual folder功能:在根目录书签Tab处按右键弹出右键菜单,选Virtual folder模式(切换成Virtual folder以后原来此tab保存的Server root不会丢失,可以随时再切回来)。

    切换后会看到如下界面:

    往虚拟文件夹添加文件有两种方法:
    1. 通过Add按钮的打开文件对话框选取文件添加(支持多选)。
    2. 直接在资源管理器内圈选一批文件,然后拖拽到YaTFTPSvr窗口内(推荐)。
    对于不需要的文件可以选中后点Delete移出列表。按住Shift/Ctrl键可以多选。文件仅会从列表中删除不会从磁盘上物理删除。如果需要清理掉文件列表中已经不存在的文件(比如一些已经被删掉了的project),可以点Purge将已经不存在的文件自动从列表中剔除。

    每次退出YaTFTPSvr的时候所有的配置都会自动保存到ini中,精心构造的Virtual folder列表不会丢失。

    文件别名:

    虚拟目录下的文件不允许重名。不过如果你需要把两个同名文件放在同一个虚拟目录下,可以给文件起个别名。另外一个用途是有些tool-chain配置的编译出来的文件名又臭又长,一辈子也记不住。所以可以给它起个简短的别名容易下载。

    文件别名只能在Virtual folder模式下使用。单选一个虚拟文件项,右键菜单中就能找到Rename即可修改别名:

    修改成功后Client端即可通过别名访问到对应的文件。

    Server root书签预览:

    书签预览增加了对Virtual folder模式的支持,鼠标指针放在处于Virtual folder模式的Tab上即显示其对应的虚拟文件夹的部分内容,方便寻找和切换自己需要的根目录配置:


    文件拖拽支持:


    使用拖拽功能可以快速设置根目录或像虚拟文件列表添加文件:
    • 在Virtual folder模式下,拖入窗口的文件会添加到虚拟文件列表;
    • 在Real folder模式下,根目录会自动设置为拖入文件所处的目录。
    为了便于拖拽,建议在窗口标题栏的右键菜单中打开Stay on Top将窗体暂时置顶:

    东西在我的盒子里面下载,老地方。
    15-2-2009

    TFTP Server更新

    时隔正好1年,又开始改进我的简陋的TFTP Server了。网上的TFTP Server一大堆,一直在考虑是不是要改个比较有个性的名字,比如叫Yet Another TFTP Server啥的,或者干脆叫YaTFTPSvr,看起来比较NB一点~~

    这次的改动源于我最近调试的痛苦。最近正在写一个OS内核,需要不断地往板子上下装编译好的内核以及需要在这个内核上加载运行的ELF文件。还有一个麻烦的是我用的BDI2000调试器正好又要通过TFTP获取配置文件和CPU初始化参数……这些文件都分布在不同的目录里。就算我原来的TFTP Server支持多Tab快速切换Server Root,也还是在调试时手忙脚乱切得眼花。所以这次终于下定决心加入了Virtual folder功能。

    加入Virtual Folder功能后,正常情况下TFTP Server的界面和使用都没有任何变化。还是不需要任何配置的傻瓜用法。只是在Tab上右键单击的时候,可以将这个Tab切换到Virtual folder模式:

    切换到Virtual folder模式后,服务器的Root就成了一个虚拟文件列表。把需要下载的文件通过Add或者直接拖拽丢到列表里面就可以了:

    这样就可以把分散在不同地方的文件都拖进来,这样在通过TFTP Client下载的时候看上去就好像是位于同一个root目录下一样,方便。另外列表中的文件可以指定虚拟文件名。有时候Make出来的目标文件可能是一个很长很诡异的名字,下载的时候我总是要跳过去Copy一把文件名往Client端贴。有了重命名功能后,可以给名字又臭又长的文件指定一个简短好记的别名,比如我把第一个文件命名为abc,则Client端就可以通过abc这个名字来下载到test.c:

    还在测试中~~未发布。不过也没几个人会用得着(﹀_﹀")
    29-12-2008

    Megatops ProCoder Font无敌编程字体粗体版

    在命令行界面的时候我喜欢粗笔画的字体显示(类似于用Fixedsys的那种感觉)。不过仅仅将终端软件的界面字体设置成粗体是不够的,因为如果中文也被显示成粗体的话看上去比较恶心不说,有的终端软件的字体宽度还会计算错掉(中文的粗体和非粗体并不等宽)。所以最终决定将Megatops ProCoder Font 1.0的GB2312版拿来修改,将标准体部分也替换成粗体字型。这样看上去的粗度就和Fixedsys的差不多了,不喜欢在终端里面用细字型的朋友,这回也没啥理由不用俺的无敌字体了吧哇哈哈。

    在命令行界面中的使用效果如下:英文部分粗体显示,中文部分正常显示,所以中英文还是可以做到严格等宽。当然,如果有人习惯了在代码编辑器里面也用Fixedsys的,把这个字体放在代码编辑器里面用也是OK的。

    在我的盒子里面下载,老地方。也是需要导入里面的注册表后重启才能正常显示中文。
    ps:这套字体的粗体部分被我锁了不准Windows自作主张将其伪加粗。想想Fixedsys在粗体时的表现吧……
    23-12-2008

    Megatops BinCalc二进制计算器v1.0.3更新

    主要更新:
    • ASCII字符支持剪贴板
    • 完善热键支持,绝大部分功能可以通过热键操作

    下载:Softpedia
    16-11-2008

    关于Megatops BinCalc RPN计算器的说明

    最近收到几个好心人发来的邮件,指出我的BinCalc存在低级BUG,即1+1算出来不等于2~~鉴于存在这种误解的人之多,俺不得不爬出来澄清一下~~我的Megatops BinCalc当中的计算器是RPN Calculator!(同学们难道没有发现BinCalc的计算器没有等号嘛~~囧rz)

    如果你是学软件出身的但是居然没有听说过RPN,那你一定是没听课也没做作业的了~~逆波兰表达式的概念最早出现在C圣经的课后习题里面。不过如果你学的是叹号强那本误人子弟的烂书……那也最迟会在编译原理里面看到它。如果你是学硬件出身的~~俺也不是很清楚硬件课程有没有提到RPN的,但是感觉应该没道理不提。

    BinCalc的RPN计算器基本上是和惠普计算器的RPN操作相同的,是XYTZ 4寄存器的经典RPN(惠普的计算器有的型号多一个LASTx寄存器,但是换汤不换药)。和惠普的计算器相比,BinCalc的RPN计算器费了大力气硬是挤下了一个可视化的堆栈,用起来应该是比只有一行显示的那种HP计算器好用多了。RPN的原理极其简单,简述如下:

    BinCalc的RPN计算器有XYZT四个寄存器。在界面的多进制面板中显示和输入的都是X寄存器的内容;YZT三个寄存器可以看成是个堆栈,其中T是栈顶寄存器(可以作为常数寄存器来使用)。

    按ENTER键是执行压栈操作~~不是当作等号用的啦(╯﹏╰),所以你1+1 ENTER~~结果当然不会是2~~

    如上图,按了ENTER以后,X寄存器的内容会被压入堆栈(YZT),原来T寄存器的内容因为堆栈上溢而被挤出去丢掉了。每个寄存器都有一套自己的单目运算按钮,可以在不需要调整到X的前提下对每个寄存器直接进行算术移位和取反等操作(BinCalc无敌可视化堆栈的威力)。最右边三个按钮是用于调整堆栈的,从上到下分别是:寄存器循环上移(相当于HP的R↑键)、寄存器循环下移(HP的R↓键)、XY寄存器互换(HP的X<>Y键)。另外CLx是X寄存器清零,CLR是清空所有寄存器(HP的CLΣ键)。这几个都好理解,自己试试就明白。

    做二元计算的时候,情况是这样的(比如做+计算):

    整个计算的过程你可以看作是:按下双目算符后,就会从堆栈中弹出操作数Y,与X寄存器一块进行相应的计算,计算的结果放在X寄存器内。在退栈的时候可以看到T寄存器始终是保持不变的,所以实际使用的时候T寄存器可以当作常数寄存器来用。比如有时候经常要算XXX和几个1024相乘或者相除的结果。这时候就可以把1024一直压到T寄存器去,然后就能源源不断地从堆栈中弹出1024这个数进行计算了。

    RPN的双目计算乍一看似乎很深奥的样子,实际上完全可以看作是竖式计算:

    竖式计算好像小学1年级开始就玩得很熟了~~应该不用再废话。

    另外,BinCalc在如下高亮位置有右键菜单,其他就再没有什么Readme没有提到的隐藏的机关了~~

    最后~~贴一个史上最经典的程序员专用计算器:HP-16C。可惜HP的11/12/15/16这一系列计算器最终仅有12C活的滋润一直生产到现在(现在还能买到,基本成为金融计算器的工业标准了)。15和16都停产好久了~~现在被当作古董卖价格有点夸张了。

    12-11-2008

    无敌二进制计算器Megatops BinCalc更新

    更新到1.0.2,完全是BUG修订。之前的版本移位运算有问题:X寄存器相关的移位操作都是逻辑移位,而Y、Z、T寄存器的都是算术移位,不一致。这个版本将所有的移位操作都改为算术移位。另外修正了一个小小的ASCII Char焦点提示错误。

    最新版本在我的文件盒子里下载,或者翻墙到BinCalc的主页:http://bincalc.googlepages.com/下载。Softpedia的因为我很懒得提交更新说明,所以还是旧版本。

    ★ 2008年11月18日 今天提到Softpedia去了,可以下载了:http://www.softpedia.com/get/Science-CAD/Megatops-BinCalc.shtml

    31-8-2008

    Megatops ProCoder Font GB2312版本

    发现如果我的这个字体不支持GB2312编码的话,在不少软件里面用起来确实麻烦。比如:在SecureCRT里面用,Copy的时候无法把中文拷贝出来(这个问题能忍无所谓,反正我在终端里面从来不用中文);在Hex Workshop里面,不知道这个鬼佬的玩意为啥非得只能用支持GB2312字体;在Beyond Compare 3里面,如果不支持GB2312的用起来计算中文的宽度会出问题……主要是Beyond Compare 3的这个问题,令我忍无可忍,终于下决心改之。

    最终的成品放到我的盒子里面了(不懂盒子的自己多翻翻我的blog~~),字体名为Megatops ProCoder Font 1.0 GB2312。用的时候必须要导入压缩包内的注册表,重启一把才行。重启后即可正常使用支持GB2312编码的无敌等宽字体了~~

    btw:我盒子里面的SlickEdit宏已经更新到v13.0.2的版本,请有兴趣的在升级了SE以后down下来再Merge。
    16-8-2008

    Megatops BinCalc日后的发布地址

    因为GooglePages看上去没啥解封的希望,所以我把转正了的BinCalc提交到Softpedia去了。不过这个Softpedia确实挺赞的,反应迅速,并且真的把东西跑了一把有检查过。至少上面的截图不是我提交的那个是他们自己跑了截的。

    试验了一下,国内能正常访问和下载:http://www.softpedia.com/get/Science-CAD/Megatops-BinCalc.shtml

    另外,100% Clean!

    10-8-2008

    Megatops BinCalc 1.0.0正式版发布

    随着最后一个IPv4地址显示功能的加入,我的Megatops BinCalc终于完整实现了我最初写在Feature List里的所有功能。因此我决定从这个版本开始为BinCalc转正,正式设置版本号为1.0.0。



    相对于上次发布的v0.2f版的改进主要有:

    位指示器增加了2^n提示功能。显示位的Tool-tip的时候除了显示位序号还同时显示对应的2^n值。在设置一些基址寄存器或者调试CPU的MMU TLB表项的时候这个功能很方便:



    ASCII字符显示增加输入功能。原本我增加ASCII Char显示功能纯粹是因为界面里面右边那块实在是太空了不知道该放点什么,还以为不可能有人用这种功能的。不过前几天有个鬼佬强烈建议俺增加ASCII输入功能,因为他居然用BinCalc来调试某种基于字节流的通讯应用( ̄口 ̄)!!。所以俺想了想估计那些经常做串口之类驱动的有可能还需要这个功能,于是就一块加上了。使用Tab键或者双击ASCII显示可以将输入焦点(黄色背景高亮)转移过去,然后敲键盘就可以了。因为是面向字节流调试的,所以Char输入是这个计算器里面唯一不在溢出时阻止输入的地方。你可以连续不断地往里面敲字母,BinCalc将字节输入按照FIFO原则处理。



    最后增加的一个功能就是IPv4地址显示和输入。在界面设计的时候我真是绞尽脑汁,最终使用了复用二进制数显示区的办法来硬是挤进了这个功能(这个功能迟迟没有弄主要是因为界面原因)。因为根据我个人经验,如果你要算得是IP掩码那用位指示器就已经足够了,根本懒得去看那一大串0和1。



    IP地址的输入方式也很伤脑筋,因为我很不想用Windows标准的那种文本框输入。最终我设计和实现的这个输入方式还是与计算器的输入方式统一了:输入的时候IP地址从低位往高位涨。IP地址只能用键盘输入,使用感觉与BinCalc其他进制的输入方式统一,用起来感觉挺好的也不会觉得怪怪的。

    IP操作主要是用于IP报文解析调试或者是计算IP地址掩码的时候。但是我自己用了一阵子后很快就用IP显示取代了原来的二进制数显示了:因为IPv4地址点分十进制的显示方式正好直观地显示了32bit整型中每个字节的十进制形式,结合右边的ASCII字符显示可以让你直接看到每个字符的十进制Code。

    在我的盒子里面可以找到最新版本的下载。另外我也给BinCalc做了个官方主页:http://bincalc.googlepages.com。主页是鸟语的,没打算做中文版。因为Google Pages被GFW捂得十分严实,中文版做了也白做~~

    ★ 2008年8月11日星期一:发现之前上传盒子的版本弄错了,盒子上的不是最终版本。最终版本版本号为:1.0.0.166。已经下载了的麻烦再检查一下。
    6-7-2008

    长得很Win的gVIM

    今晚配置了一把Windows版的gVIM,现在长得很Modern了~~



    看起来已经彻底像是个Windows下的编辑器了吧(# ̄▽ ̄#)
    6-6-2008

    几款TTF等宽字体秀

    今天整理字体,翻出了俺收藏的这些等宽TTF矢量字体(点阵字俺一直用俺的DIY作品,无视其他( ̄^ ̄))。大家有兴趣可以看看弄来试试。以下都是SlickEdit 2008中11pt字号的显示效果,按照字母顺序排序。字体都是Google来的,自己可以找到。


















    5-3-2008

    Megatops ProCoder Font字体主页上线

    文字部分以前就写好了,今晚终于下定决定放到Google Pages上去了。不过这不意味着我接着会开始积极更新这套字体了——相反,新的开发任务又要开始,我这只是赶着最后一个清闲的晚上,把最后还没放上来的东西放上来罢了(╯﹏╰)。估计在之后的好几个月,可能都不会再有什么空闲时间来维护更新这套字体了。如果各位有什么不满意的地方,就先忍着吧~~忍个半年等我缓过劲来了,俺就会回来更新了~~

    页面位置:http://zhaojie.ding.googlepages.com/megatopsprocoderfont

    感谢简单好用的Google Pages,在我的个人主页空间没掉4年以后让我再次有了向网上挂页面的动力~~
    26-2-2008

    猪哥的Megatops ProCoder 1.0字体新品发布

    因为自己时不时也用用Ultraedit、EmEditor、EditPlus这样的编辑器,发现原来的ProCoder字体覆盖了128-255编码范围和中文字体冲突在这些不能正确计算宽度的编辑器里面确实还是挺麻烦的。所以简单裁剪了一个仅包含0-127范围的Lite版Megatops ProCoder字体。可以正常调用宋体显示全角引号、单引号、省略号等。当然,128及以上的西欧字符被裁掉了,所以这个版本无法正确显示德文和法文。如果你有这种需要就得使用没有裁过的完整版。所以我是建议你两个版本都安装,在类似于EmEditor这种能够为不同字符集指定字体的编辑器里面就可以无痛切换。

    以下是在EditPlus中Lite版本的显示效果,因为已经完全裁掉了0x7F以上的字符,所以全角符号完全由中文宋体支持:



    和原来的Full版可以共存,直接安装即可。点击这里下载

    ★ Megatops ProCoder正如其名:仅仅面向有长时间编码或屏幕代码阅读需求的专业程序员设计,不明白其设计目的的麻烦绕行~~
    15-2-2008

    C语言的inline

    转以前我用Docbook写的一篇关于C语言inline关键字使用的文章。唉,要是能用docbook直接写Blog就好了。用得越多发现Docbook这个东西真是越好用啊~~
     
    本文介绍了GCC和C99标准中inline使用上的不同之处。inline属性在使用的时候,要注意以下两点:
    1. inline关键字在GCC参考文档中仅有对其使用在函数定义(Definition)上的描述,而没有提到其是否能用于函数声明(Declare)。

      从inline的作用来看,其放置于函数声明中应当也是毫无作用的:inline只会影响函数在translation unit(可以简单理解为C源码文件)内的编译行为,只要超出了这个范围inline属性就没有任何作用了。所以inline关键字不应该出现在函数声明中,没有任何作用不说,有时还可能造成编译错误(在包含了sys/compiler.h的情况下,声明中出现inline关键字的部分通常无法编译通过);

    2. inline关键字仅仅是建议编译器做内联展开处理,而不是强制。在gcc编译器中,如果编译优化设置为-O0,即使是inline函数也不会被内联展开,除非设置了强制内联(__attribute__((always_inline)))属性。

    1. GCC的inline

    gcc对C语言的inline做了自己的扩展,其行为与C99标准中的inline有较大的不同。

    1.1. static inline

    GCC的static inline定义很容易理解:你可以把它认为是一个static的函数,加上了inline的属性。这个函数大部分表现和普通的static函数一样,只不过在调用这种函数的时候,gcc会在其调用处将其汇编码展开编译而不为这个函数生成独立的汇编码。除了以下几种情况外:

    • 函数的地址被使用的时候。如通过函数指针对函数进行了间接调用。这种情况下就不得不为static inline函数生成独立的汇编码,否则它没有自己的地址。

    • 其他一些无法展开的情况,比如函数本身有递归调用自身的行为等。

    static inline函数和static函数一样,其定义的范围是local的,即可以在程序内有多个同名的定义(只要不位于同一个文件内即可)。

    注意

    gcc的static inline的表现行为和C99标准的static inline是一致的。所以这种定义可以放心使用而没有兼容性问题。

    要点:

    • gcc的static inline相对于static函数来说只是在调用时建议编译器进行内联展开;

    • gcc不会特意为static inline函数生成独立的汇编码,除非出现了必须生成不可的情况(如通过函数指针调用和递归调用);

    • gcc的static inline函数仅能作用于文件范围内。

    1.2. inline

    相对于C99的inline来说,GCC的inline更容易理解:可以认为它是一个普通全局函数加上了inline的属性。即在其定义所在文件内,它的表现和static inline一致:在能展开的时候会被内联展开编译。但是为了能够在文件外调用它,gcc一定会为它生成一份独立的汇编码,以便在外部进行调用。即从文件外部看来,它和一个普通的extern的函数无异。举个例子:

    foo.c:
    
    /* 这里定义了一个inline的函数foo() */
    inline foo() {
        ...;   <- 编译器会像非inline函数一样为foo()生成独立的汇编码
    }
    
    void func1() {
        foo(); <- 同文件内foo()可能被编译器内联展开编译而不是直接call上面生成的汇编码
    }

    而在另一个文件里调用foo()的时候,则直接call的是上面文件内生成的汇编码:

    bar.c:
    
    extern foo(); <- 声明foo(),注意不能在声明内带inline关键字
    
    void func2() {
        foo();    <- 这里就是直接call在foo.c内为foo()函数生成的汇编码了
    }
    重要

    虽然gcc的inline函数的行为很好理解,但是它和C99的inline是有很大差别的。请注意看后面对C99 inline的描述(第 2.2 节 “inline”),以及如何以兼顾GCC和C99的方式使用inline函数。

    要点:

    • gcc的inline函数相对于普通extern函数来说只是在同一个文件内调用时建议编译器进行内联展开;

    • gcc一定会为inline函数生成一份独立的汇编码,以便其在本文件之外被调用。在别的文件内看来,这个inline函数和普通的extern函数无异;

    • gcc的inline函数是全局性的:在文件内可以作为一个内联函数被内联展开,而在文件外可以调用它。

    1.3. extern inline

    GCC的static inline和inline都很好理解:看起来都像是对普通函数添加了可内联的属性。但是这个extern inline就千万不能想当然地理解成就是一个extern的函数+inline属性了。实际上gcc的extern inline十分古怪:一个extern inline的函数只会被内联进去,而绝对不会生成独立的汇编码!即使是通过指针应用或者是递归调用也不会让编译器为它生成汇编码,在这种时候对此函数的调用会被处理成一个外部引用。另外,extern inline的函数允许和外部函数重名,即在存在一个外部定义的全局库函数的情况下,再定义一个同名的extern inline函数也是合法的。以下用例子具体说明一下extern inline的特点:

    foo.c:
    
    extern inline
    int foo(int a)
    {
        return (-a);
    }
    
    void func1()
    {
        ...;
        a = foo(a);   ①
        p_foo = foo;  ②
        b = p_foo(b); ③
    }

    在这个文件内,gcc不会生成foo函数的汇编码。在func1中的调用点①,编译器会将上面定义的foo函数在这里内联展开编译,其表现类似于普通inline函数。因为这样的调用是能够进行内联处理的。而在②处,引用了foo函数的地址。但是注意:编译器是绝对不会为extern inline函数生成独立汇编码的!所以在这种非要个函数地址不可的情况下,编译器不得不将其处理为外部引用,在链接的时候链接到外部的foo函数去(填写外部函数的地址)。这时如果外部没有再定义全局的foo函数的话就会在链接时产生foo函数未定义的错误。

    假设在另一个文件里面也定义了一个全局函数foo:

    foo2.c:
    
    int foo(int a)
    {
        return (a);
    }

    那么在上面那个例子里面,后面一个对foo函数地址的引用就会在链接时被指到这个foo2.c中定义的foo函数去。也就是说:①调用foo函数的结果是a=-a,因为其内联了foo.c内的foo函数;而③调用的结果则是b=b,因为其实际上调用的是foo2.c里面的foo函数!

    extern inline的用法很奇怪也很少见,但是还是有其实用价值的。第一:它可以表现得像宏一样,可以在文件内用extern inline版本的定义取代外部定义的库函数(前提是文件内对其的调用不能出现无法内联的情况);第二:它可以让一个库函数在能够被内联的时候尽量被内联使用。举个例子:

    在一个库函数的c文件内,定义一个普通版本的库函数libfunc:

    lib.c:
    
    void libfunc()
    {
        ...;
    }

    然后再在其头文件内,定义(注意不是声明!)一个实现相同的exterin inline的版本:

    lib.h:
    
    extern inline libfunc()
    {
        ...;
    }

    那么在别的文件要使用这个库函数的时候,只要include了lib.h,在能内联展开的地方,编译器都会使用头文件内extern inline的版本来展开。而在无法展开的时候(函数指针引用等情况),编译器就会引用lib.c中的那个独立编译的普通版本。即看起来似乎是个可以在外部被内联的函数一样,所以这应该是gcc的extern inline意义的由来。

    但是注意这样的使用是有代价的:c文件中的全局函数的实现必须和头文件内extern inline版本的实现完全相同。否则就会出现前面所举例子中直接内联和间接调用时函数表现不一致的问题。

    重要

    gcc的extern inline函数的用法相当奇怪,使用的范围也非常狭窄:几乎没有什么情况会需要用它。

    在C99中,也没有关于extern inline这样的描述,所以不建议大家使用extern inline,除非你明确理解了这种用法的意义并且有充足的理由使用它!

    要点:

    • gcc绝对不会为extern inline的函数生成独立汇编码

    • extern inline函数允许和全局函数重名,可以在文件范围内替代外部定义的全局函数

    • extern inline函数的应用范围十分狭窄,而且行为比较奇怪,不建议使用

    2. C99的inline

    以下主要描述C99的inline与Gcc不同的部分。对于相同的部分请参考GCC inline的说明。

    2.1. static inline

    同GCC的static inline(第 1.1 节 “static inline”)。

    2.2. inline

    C99的inline的使用相当令人费解。当一个定义为inline的函数没有被声明为extern的时候,其表现有点类似于gcc中extern inline那样(C99里面这段描述有点晦涩,原文如下):

    If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

    即如果一个inline函数在文件范围内没有被声明为extern的话,这个函数在文件内的表现就和gcc的extern inline相似:在本文件内调用时允许编译器使用本文件内定义的这个内联版本,但同时也允许外部存在同名的全局函数。只是比较奇怪的是C99居然没有指定编译器是否必须在本文件内使用这个inline的版本而是让编译器厂家自己来决定,相当模糊的定义。

    如果在文件内把这个inline函数声明为extern,则这个inline函数的表现就和gcc的inline一致了:这个函数即成为一个“external definition”(可以简单理解为全局函数):可以在外部被调用,并且在程序内仅能存在一个这样名字的定义。

    下面举例说明C99中inline的特性:

    inline double fahr(double t)
    {
        return (9.0 * t) / 5.0 + 32.0;
    }
    
    inline double cels(double t)
    {
        return (5.0 * (t - 32.0)) / 9.0;
    }
    
    extern double fahr(double);   ①
    
    double convert(int is_fahr, double temp)
    {
        return is_fahr ? cels(temp) : fahr(temp);   ②
    }

    在上面这个例子里,函数fahr是个全局函数:因为在①处将fahr声明为extern,因此在②处调用fahr的时候使用的一定是这个文件内所定义的版本(只不过编译器可以将这里的调用进行内联展开)。在文件外部也可以调用这个函数(说明像gcc的inline一样,编译器在这种情况下会为fahr生成独立的汇编码)。

    而cels函数因为没有在文件范围内被声明为extern,因此它就是前面所说的“inline definition”,这时候它实际上仅能作用于本文件范围(就像一个static的函数一样),外部也可能存在一个名字也为cels的同名全局函数。在②处调用cels的时候编译器可能选择用本文件内的inline版本,也有可能跑去调用外部定义的cels函数(C99没有规定此时的行为,不过编译器肯定都会尽量使用文件内定义的inline版本,要不然inline函数就没有存在的意义了)。从这里的表现上看C99中未被声明为extern的inline函数已经和gcc的extern inline十分相似了:本文件内的inline函数可以作为外部库函数的替代。

    重要

    C99标准中的inline函数行为定义的比较模糊,并且inline函数有没有在文件范围内被声明为extern的其表现有本质不同。如果和gcc的inline函数比较的话,一个被声明为extern的inline函数基本等价于GCC的普通inline函数;而一个没有被声明为extern的inline函数基本等价于GCC的extern inline函数

    因为C99的inline函数如此古怪,所以在使用的时候,建议为所有的inline函数都在头文件中创建extern的声明:

    foo.h:
    
    extern foo();

    而在定义inline函数的c文件内include这个头文件:

    foo.c:
    
    #include "foo.h"
    
    inline void foo()
    {
        ...;
    }

    这样无论是用gcc的inline规则还是C99的,都能得到完全相同的结果:foo函数会在foo.c文件内被内联使用,而在外部又可以像普通全局函数一样直接调用。

    2.3. extern inline

    C99没有见到extern inline的用法。

    27-1-2008

    猪哥牌TFTP Server出炉

    猪哥的TFTP Server终于处于实用状态了,基本上没啥大问题,放出来下载。

    为了避免不明用处的人瞎下载,这里说明一下下载对象:
    1. 知道TFTP Server和FTP Server就像牛和马一样是两码事的,且
    2. 经常需要通过TFTP协议往开发板子上面下装程序的,且
    3. TFTP Server通常仅仅跑在自己的机子上自己用,不会被一堆人共同蹂躏的,且
    4. 很讨厌复杂操作,只想要个点开就能跑的Server程序的,且
    5. 除了要求TFTP Server能提供上传下载以外不希望再有其他什么花哨功能的,且
    6. 经常要在最常用的几个root目录之间切换的,且
    7. 对于自己现用的TFTP Server觉得有点不爽的
    如果你满足以上所有条件,那么你就可以下载我的TFTP Server试试看了。我的TFTP Server就是以最简界面,最简功能,最简操作的思想设计的。提供的功能如下:
    • 无需配置即可用,运行后即在69端口侦听,默认根目录为程序运行的目录
    • 多路径保存:最多保存8个常用根目录满足通常调试需要。通过Tab快速切换,右键单击Tab可以重命名
    • 双击地址栏可以在资源管理器内打开Server根目录
    • 带有历史记录的地址栏,支持20个历史地址,历史地址输入时支持自动完成
    • 支持最小化到系统托盘,用气泡提示传输开始和结束
    • 彩色的分色服务器Log显示,凸显失败的传输
    • 实时传输进度显示(已传输字节数和百分比),下载时看起来比较有成就感:)
    • 支持多线程上传和下载,支持RFC 1350、RFC 1782、RFC 1783
    Megatops TFTP Server界面截图如下:



    此处下载
     
    *