| 猪哥 的个人资料猪哥的Blog日志列表留言簿 | 帮助 |
|
2008/2/26 猪哥的Megatops ProCoder 1.0字体新品发布因为自己时不时也用用Ultraedit、EmEditor、EditPlus这样的编辑器,发现原来的ProCoder字体覆盖了128-255编码范围和中文字体冲突在这些不能正确计算宽度的编辑器里面确实还是挺麻烦的。所以简单裁剪了一个仅包含0-127范围的Lite版Megatops ProCoder字体。可以正常调用宋体显示全角引号、单引号、省略号等。当然,128及以上的西欧字符被裁掉了,所以这个版本无法正确显示德文和法文。如果你有这种需要就得使用没有裁过的完整版。所以我是建议你两个版本都安装,在类似于EmEditor这种能够为不同字符集指定字体的编辑器里面就可以无痛切换。 以下是在EditPlus中Lite版本的显示效果,因为已经完全裁掉了0x7F以上的字符,所以全角符号完全由中文宋体支持: ![]() 和原来的Full版可以共存,直接安装即可。点击这里下载 ★ Megatops ProCoder正如其名:仅仅面向有长时间编码或屏幕代码阅读需求的专业程序员设计,不明白其设计目的的麻烦绕行~~ 2008/2/24 最好的中文和英文TTS语言库经过尝试后俺基本确定了现阶段最值得推荐的SAPI 5 TTS引擎:NeoSpeech的VW Paul和VW Lily! 2008/2/15 C语言的inline转以前我用Docbook写的一篇关于C语言inline关键字使用的文章。唉,要是能用docbook直接写Blog就好了。用得越多发现Docbook这个东西真是越好用啊~~
本文介绍了GCC和C99标准中inline使用上的不同之处。inline属性在使用的时候,要注意以下两点:
gcc对C语言的inline做了自己的扩展,其行为与C99标准中的inline有较大的不同。 GCC的static inline定义很容易理解:你可以把它认为是一个static的函数,加上了inline的属性。这个函数大部分表现和普通的static函数一样,只不过在调用这种函数的时候,gcc会在其调用处将其汇编码展开编译而不为这个函数生成独立的汇编码。除了以下几种情况外:
static inline函数和static函数一样,其定义的范围是local的,即可以在程序内有多个同名的定义(只要不位于同一个文件内即可)。
相对于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的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版本的实现完全相同。否则就会出现前面所举例子中直接内联和间接调用时函数表现不一致的问题。
以下主要描述C99的inline与Gcc不同的部分。对于相同的部分请参考GCC inline的说明。 同GCC的static inline(第 1.1 节 “static inline”)。 C99的inline的使用相当令人费解。当一个定义为inline的函数没有被声明为extern的时候,其表现有点类似于gcc中extern inline那样(C99里面这段描述有点晦涩,原文如下):
即如果一个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函数可以作为外部库函数的替代。
2008/2/14 猪哥修改版搜狗拼音3.2——支持华丽Cleartype!下周一就要开始痛苦的上班了,趁着还有2天假,赶紧研究了一下我想改已久的搜狗拼音输入法。 这搜狗拼音和以前老版本的紫光一个德性:不支持Cleartype。搞得我根本没法用雅黑来做输入法的字体。而宋体在调大以后就不堪入眼,所以输入时只好一直忍受小小的16号宋体,即使是在我可怜的14寸1400×1050的显示器上也不得不这样忍受。 不过经过俺今晚天才、辉煌而又成功地修改,搜狗拼音不支持Cleartype已经成为了历史。修改方法是用IDA Pro反汇编( ̄口 ̄)!!,我反啊反,找到了搜狗设置输入栏字体的地方。看了看代码,前看后看,还是没明白为啥搜狗非要关掉Cleartype支持。既然没发现啥危险,我就打开他算了。另外发现实际上搜狗也能像拼音加加那样支持是否使用粗体斜体什么的显示的,只是搜狗很恶心地把英文字母硬编码用粗体,中文硬编码用正常体显示罢了~~难道是以前紫光遗留下来的历史问题?!(紫光是我唯一见到的字体配置和搜狗一样怪的输入法)。 修改的位置如下: SogouPY.ime: 0x51C5D: 04 → 00 0x51EDD: 04 → 00 0x51DAD: 04 → 00 config.exe: 0x3A4bD: 04 → 00 0x3A60D: 04 → 00 0x3A73D: 04 → 00 不想自己改的,下载我改好的版本:点击下载 注意,上面修改只能用于搜狗拼音3.2正式版!!使用后搜狗拼音在系统打开Cleartype的情况下也会使用Cleartype渲染字体: ![]() 不只是可以用用雅黑之类的字体,在大字体显示的时候我的修改版本也有明显优势。以下是修改前官方原版的搜狗显示效果: ![]() 这是修改之后的效果: ![]() 明显,打开Cleartype支持以后的效果要好很多。奇怪的是搜狗不但不支持,更是在代码内费心故意关闭了Cleartype支持~~不清楚开发者是怎么想的啊(﹀_﹀") |
|
|