当时就感觉可能没有太多时间(尽管应该会需要很久)来给我学习h.264,但是也太快了,甚至我买的书都还在路上呢,就要换方向了。现在开始做工具。老总是肯定准备把我打造成通吃天地人(服务器,客户端,工具,做网络游戏程序的还有其他的一块吗?)三界的全能打工者了。。。。。 作为打工者,自然是有什么工作做什么贝,又没得选择。 虽然我的兴趣实际在网络,linux和系统的底层,不过Windows SDK, MFC学得本来又不差,工作也不是不能做好。现在来看,只能是工作上老老实实用MFC了,工作之余我再来自己学习linux和网络吧。。。。。。。。。。向自己适应环境的能力(其实是向环境妥协的能力)致敬。
		 阅读全文.... 
   
  
    
    
 公司还真看的起我。。。。。。。。对于非计算机专业毕业的我,一开始就做错误dump,文件系统,然后写了几个服务器,现在安排我看公司以前写的h264的编解码实现。。。。。不知道这个过程能够持续多久,不知道公司能给我多久时间去了解和消化h.264的东西,不过,谁都知道,这不是一两天就可以完成的任务,希望不要像为游戏加lua的脚本模块一样半途而废。。。。。 视频牵涉到的东西比lua脚本模块牵涉到的东西实在是多了太多太多,还有那么多算法。。。。看到离散余弦变换的时候还是感觉挺熟悉的:)我的数字图像处理当年可是89分:)可是其他的东西嘛。。。。完全不懂。。。。。 多给我点时间啊,让我吃透它。。。。。。
		 阅读全文.... 
   
  
    
    
 
 
 
 
一天一个 C Run-Time Library  函数  (7)    asctime(时间函数)  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
msdn:  
Convert a tm  time structure to a character 
string. These functions are deprecated because more secure versions are 
available; see asctime_s,   
 
 
char 
  *asctime(  
    const struct tm *timeptr   
); 
 
 
 
测试程序:  
#include  <stdio.h>  
#include  <time.h>  
  
  
  
int  main ( void  ) 
{ 
  
     time_t  ltNow  = time (NULL );
     struct  tm * 
lptmNow  = localtime (<Now );
  
     const  char * 
lpszNow  = asctime (lptmNow );
  
     
     printf ("%s" ,lpszNow );
  
  
     return  0;
} 
  
  
说明:  
asctime 是非常使用的函数,与 time(),localtime , gmtime , mktime ,ctime 一起构成了 C 语言世界的时间概念。 C 中的格林威治时间体系就是由这几个函数来完成的。 time_t 类型是用来沟通这些函数的桥梁。说明一下, localtime 在转换的时候是根据本地 locale 来转换的, gmtime 就是转换标准的格林威治时间,(似乎从结果上来看就是转换成了伦敦时间)。顺便说一下,以 _t 结尾的类型定义虽然你在 Windows 中看到是可能是简单的 int 型,但是即使这样,作为可移植的程序开发,还是应该用原来的类型定义 , 这样碰到不同实现的时候不至于会导致错误,比如 windows 中现在 time_t 现在默认的就是 int64 了。 
与此类似的类型还有 pid_t,win_t 等 
实现:  
static  _TSCHAR  * __cdecl  store_dt  ( 
     REG1  _TSCHAR  *p ,
     REG2  int  val 
     )
{ 
     *p ++ = (_TSCHAR )(_T ('0' ) + val  / 
10);
     *p ++ = (_TSCHAR )(_T ('0' ) + val  % 
10);
     return (p );
} 
  
     REG2  _TSCHAR  *p  = buffer ;
     int  day , mon ;
     int  i ;
     day  = tb ->tm_wday  
* 3;       /* 
index to correct day string */ 
     mon  = tb ->tm_mon  * 
3;        /* 
index to correct month string */ 
     for  (i =0; i  < 3; i ++,p ++) {
         *p  = 
*(__dnames  + day  
+ i );
         *(p +4) 
= *(__mnames  + mon  
+ i );
     }
  
     *p  = _T (' ' );            /* blank 
between day and month */ 
  
     p  += 4;
  
     *p ++ = _T (' ' );
     p  = store_dt (p , tb ->tm_mday );    /* day of the 
month (1-31) */ 
     *p ++ = _T (' ' );
     p  = store_dt (p , tb ->tm_hour );    /* hours (0-23) */ 
     *p ++ = _T (':' );
     p  = store_dt (p , tb ->tm_min );     /* minutes (0-59) 
*/ 
     *p ++ = _T (':' );
     p  = store_dt (p , tb ->tm_sec );     /* seconds (0-59) 
*/ 
     *p ++ = _T (' ' );
     p  = store_dt (p , 19 
+ (tb ->tm_year /100)); 
/* year (after 1900) */ 
     p  = store_dt (p , tb ->tm_year %100);
     *p ++ = _T ('/n' );
     *p  = _T ('/0' );
  
  
  
MS: 
这个实现是我此系列开始写以后看的源代码中最有意思的源代码了。所以不惜编程源代码的分析都要讲一讲。 
很有意思的代码,淋漓尽致的体现了 C 语言指针的灵活。 
for  (i =0; i  < 3; i ++,p ++) { 
         *p  = 
*(__dnames  + day  
+ i );
         *(p +4) 
= *(__mnames  + mon  
+ i );
     }
通过对月和星期的 buf, 用这个循环完成的 6 个字符的拷贝更是很让我欣赏:) 
通过 val/10 的加上 ’0’ 的 asc 值的方式完成的默认前置 0 的赋值也是很有意思的技巧。 
     *p ++ = (_TSCHAR )(_T ('0' ) + val  / 
10);
*p ++ = (_TSCHAR )(_T ('0' ) + val  % 
10); 
  
  
gcc: 
仅仅通过一个简单的 snprintf 来实现,这估计也是大部分人的实现方式。。。。我要是真的准备实现这样一个代码也会这样实现。 
  
  
效率测试:  
很想知道到底哪个会赢。。。。不过太晚了。。。。 
  
  
相关函数:  
gmtime,     localtime,    ctime,  time,  
个人想法:  
除了宽字节版本不能使用之外,其他函数的使用自然没有任何问题。并且函数名完全一致。对于这么古老和标准的函数假如还能出现问题,估计任何做可移植程序的人都会崩溃的。放心用吧。 
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
		 阅读全文.... 
   
  
    
    
 
 
 
 
一天一个 C Run-Time Library  函数 (6 )    三角函数  
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
msdn:  
太多,不列举了。包括 acos,cos,asin,sin,atan,tan 等等 
 
 
 
测试程序:  
  
说明:  
都没有太多需要解释的,三角运算时需要的函数。 
实现:  
MS: 
我只看了 acos 的实现,完全是汇编实现的。并且可以看到 sse2 的指令集, mmx 指令集都有响应的优化。 MS 也会判断你的机器是否有此指令集。有的话就是用优化后的指令。 
  
效率测试:  
这里效率测试很有意思,可以看看两个编译器对于汇编代码的优化到什么地步。。。。但是由于我懒嘛。。。所以没有进行。 
相关函数:  
无 
个人想法:  
对于这么简单的函数自然可以自由使用了。并且在 C++ 下的话通过重载可以更简单的使用。不然就只能记得使用 f 后缀的使用方式了。比如 cosf 。。。表示浮点类型的余弦函数。 
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
		 阅读全文.... 
   
  
    
    
 
 
 
 
一天一个 C Run-Time Library  函数(5)    access 
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
msdn:  
Determines if a file 
is read-only or not. More secure versions are available; see  _access_s, _waccess_s . 
 
 
int 
  _access(  
    const char *path ,  
    int mode   
); 
int 
  _waccess(  
    const wchar_t *path ,  
    int mode   
); 
 
 
 
测试程序:  
  
说明:  
access 是个很有用的函数,非常之有用。特别是在 linux 下。对于 windows 中,似乎都没有不可读和不可执行的概念,所以相对来说使用率相对低一些。另外,最标准的测试一个文件是否存在的方式可能就是用 access 函数了,虽然真正的可以达到目的方式有很多。 
在 linux 下此函数的使用需求很大,因为 linux 的权限设置更为丰富。很多时候是否存在,可读,可写,可执行都需要判断,这样你能更容易知道你下一步该做什么,而不是真的等到某个文件打不开,写不了,执行失败时才报告错误。 
对于这么重要的函数,我没有给出示例。。。只能说我是越来越懒了,不过总是发现明明我仅仅是想看看哪些函数在 windows/linux 下都可以用,最后却变成了函数的使用说明和实现代码分析。。。。。。。。花费时间,其实也没有实际价值,因为用法可以查 msdn , man ,我贴一下也没有什么用,还是把时间用在更值得用过的地方吧。 
实现:  
windows 下主要通过 API     GetFileAttributes函数来完成。 
linux 下的实现我竟然没有找到。。。。。无语 
  
效率测试:  
此函数好像通常不太需要考虑效率,因为两个系统完全不一样,所以测试此函数效率没有任何意义。 
  
相关函数:  
  
个人想法:  
宽字节的版本照例 linux 下没有实现。其实可以总结一下,起码所有的关于文件的宽字节版本的函数 ,linux 下都没有。原因很简单, linux 虽然支持 unicode ,但是支持的不是通常 windows 下所谓的 unicode 的版本,而是 utf-8 ,所以不需要宽字节。 
在此时完全没有办法糅合,也完全没有办法放弃功能。不可能说以后编写的都是不用文件操作的东西吧?那么只能是一方妥协于另一方。我公司的做法是向微软妥协。也就是完全使用 32 位的宽字节版本的 unicode, 这样在 windows 下其实效率是最高的(因为 windows 的核心都是 unicode 了, ansi 版本的 api 需要多进行一次编码转换)。但是所有在 linux 下的文件操作都需要经过 unicode2utf8 的编码转换,还好这个转换是非常快的(起码没有编码映射的过程)。本人更喜欢 linux ,更喜欢让 windows 版本的东西经过编码转换才用。因此 linux 下的操作会更快(这就是我想要的)而 windows 版本的很多操作都需要先转换编码,带来的代价是,所有的字符串在 VS 中调试时将不能看到有意义的输出:)所有的命令行字符串中文都无法正确显示。(实际只能显示 ASCII )。纯粹个人爱好,因为我想强迫自己去熟悉 linux 下的东西。真正的工程应用假如大部分在 windows 下开发,自然是向 windows 妥协的好。 
所以,从此以后所有宽字节的文件操作命令我直接忽略。顺便忽略的还有 MS 为增强 C 语言库写的一族 _s 函数,虽然可能真的会更安全一些,但是,可移植性不需要这样特立独行的东西。直接忽略。 
最后, linux 下的函数命名遵循的是 POSIX 标准, POSIX 函数的命名没有前缀。 MS 的函数命名遵循的是 ISO 标准(据说), ISO 标准的函数命名都带前置下划线。这点纯属瞎猜。。。。来源于所有的 POSIX 函数在 MSDN 中都会有类似的文字: 
This POSIX function is deprecated beginning in 
Visual C++ 2005. Use the ISO C++ conformant _access   or 
security-enhanced _access_s   instead. 
  
  
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
		 阅读全文.... 
   
  
    
    
以前读大学的时候就捣鼓过samba,那时候寝室四台电脑,我一个人装个英文的fc4,没有办法和室友们共享文件,特别是想共享他们的电影的时候特别不方便(好像能共享的也就是电影了)。 于是当时找到了samba,当时那个痛苦啊,折腾了起码两天才基本算搞明白怎么回事,基本实现了读取windows文件的功能和让室友访问我电脑的功能。
最近再次需要在台式机与笔记本(ubuntu)共享文件的时候,自然还是想到了samba,我弄ssh只用了一下子,弄samba又用了2个晚上,而且一直是痛苦着用着。。。。因为偶尔能够登上,偶尔又登不上。。。。。痛苦至极,当然这可能是我配置的问题。以前就想过实在不行就直接驾一个ftp就好了,今天晚上正准备好好的解决一下,给我发现了原来ssh协议中有个附带的sftp协议,可以实现类似ftp的功能。那还说什么,本来就像干脆驾个ftp了,看到这样更没有犹豫了。
并且给我找到了winscp这个软件。。。。在windows下实现了类total command的界面。。。这下台式机及笔记本之间的文件共享问题总算是解决了。。。。以后再也不会痛苦了。可惜的是RSA的密钥验证方式我一直还没有弄好,小郁闷。
用winscp传输文件,用putty远程登录,完美编程的解决方案:)另外。。。虽然对于我来说不是那么重要,但是值得一提的一点是,基于ssh2协议的传输还是加过密的。包括使用sftp在内。
		 阅读全文.... 
   
  
    
    
 
 
 
 
一天一个 C Run-Time Library  函数 (4)    abs _abs64 
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
msdn:  
Calculate the absolute value. 
 
 
int abs( 
   
    int n   
); 
long 
  abs(  
    long n   
);    // C++ only 
double 
  abs(  
    double n   
);    // C++ only 
long 
  double abs( 
    long double n 
);    // C++ only 
float 
  abs( 
    float n   
);    // C++ only 
__int64 
  _abs64(  
    __int64 n   
); 
 
 
 
这里要说明的是 c++ 因为有重载的技术,所以都可以用 abs 来表示,而 C 语言里面实际还有 labs 函数,用来表示 long 类型的绝对值。 
  
测试程序:  
虽然MSDN 都有example, 但是对于这么简单的函数,就没有必要贴了。 
  
说明:  
功能很简单,也很实用的函数。以前学习 c++ 的时候有用到过,可是实际上工作以后竟然一次也没有用过。 
  
实现:  
MS: 
int  __cdecl  abs  ( 
         int  number 
         )
{ 
         return ( 
number >=0 ? number  
: -number  );
} 
gcc: 
/* Return 
the absolute value of I.   */ 
int 
abs  (int  
i ) 
{ 
     return  i  
< 0 ? -i  : i ;
} 
再次验证了一件事情,那就是gcc 和MS 的势不两立,(突然觉得把gcc 与MS 并称很奇怪,因为根本不是同一类的事物。。。。就以MS 代指VC2005 吧。。。) 
这么一个简单的函数,实现方式上几乎没有选择,即便是同样的 ?: 结构, MS 选择了判断 >= , gcc 选择了判断 < ,再次发挥我 BT 的精神,决定看一下他们生成的汇编代码。为了公正,先都在 VS2005 看看生成的代码。 
MS: 
0041140E   cmp         
 dword ptr [number],0  
00411412   jl          
 MSabs+2Fh (41141Fh)  
00411414   mov         
 eax,dword ptr [number]  
00411417   mov         
 dword ptr [ebp-0C4h],eax  
0041141D   jmp         
 MSabs+3Ah (41142Ah)  
0041141F   mov         
 ecx,dword ptr [number]  
00411422   neg         
 ecx    
00411424   mov         
 dword ptr [ebp-0C4h],ecx  
0041142A   mov         
 eax,dword ptr [ebp-0C4h] 
  
gcc: 
004113BE   cmp         
 dword ptr [i],0  
004113C2   jge         
 GCCabs+31h (4113D1h)  
004113C4   mov         
 eax,dword ptr [i]  
004113C7   neg         
 eax    
004113C9   mov         
 dword ptr [ebp-0C4h],eax  
004113CF   jmp         
 GCCabs+3Ah (4113DAh)  
004113D1   mov         
 ecx,dword ptr [i]  
004113D4   mov         
 dword ptr [ebp-0C4h],ecx  
004113DA   mov         
 eax,dword ptr [ebp-0C4h] 
DEBUG 下才能看到老实的逐句解析的代码, Release 下简单的 abs 函数调用都直接在编译期间就计算完了。说实话,即使在 DEBUG 版本中我看不出来两者有什么区别。两者在参数为正,或为负的时候都需要一次 jmp 。唯一也许有不同的可能就是 neg eax 的时候也许比 neg ecx 会快一点。(这还是个人猜想,因为毕竟 eax 是最常用也是 CPU 设计时提供最快操作的寄存器) 
  
效率测试:  
实在不想再测试效率了,对于这样简单的函数测试一百亿次也看不出什么东西。这也是我为什么去看汇编出来的东西。何况, release 的时候还被优化了呢。。。 
  
相关函数:  
无 
  
个人想法:  
对于这样简单的函数想怎么用就怎么用吧。假如用的是纯 C ,那么可能需要注意 64 位的实现是由 MS 实现的, linux 下没有。但是 c99 已经定义了新的 long long 类型的 abs 。用 gcc 的人就可以用这个,函数名为 llabs 。 
用 c++ 的话根本不需要操心类似的东西,也不需要关心到底使用 labs,llabs 还是其他,因为我们有重载。在 libstdc++ 中 abs(long) 就调用 glibc 的 labs 来完成,而 abs(long long) 在 libstdc++ 中也有实现。 
另外,不知道为什么这里即便是 C 语言的实现 MS,GCC 也都没有用习惯的宏,因此在这里, c++ 的函数调用会比 C 语言的版本快一点,因为 C++ 还有 inline 。   
今天对我来说是周末,偷懒了:)其实这么一个简单的函数也没有太多好说的。想用就用吧。 
  
write 
by  九天雁翎 (JTianLing) 
-- www.jtianling.com 
		 阅读全文.... 
   
  
    
    
 
 
 
 
一天一个 C Run-Time Library  函数 ( 3 )    abort  
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
  
头文件:   <stdlib.h> 
msdn:  
Aborts the current process and returns an error 
code. 
  
测试程序 3.1 :  
#include  <stdlib.h>  
#include  <stdio.h>  
  
int  main () 
{ 
  
     printf ("Running/n" );
  
     abort ();
  
     printf ("Still Running/n" );
     return  0;
} 
以上函数在windows 上输出为Running ,然后弹出对话框。点终止即终止程序,点忽略还会输出类似 “ This 
application has requested the Runtime to terminate it in an unusual way.  Please contact the 
application's support team for more information 。”的信息。 
在 linux 下运行输出 Running 
Aborted 
说明:  
  
总算碰到一个真正的函数了,可惜一开始真正的函数问题就复杂了,比如关于abort 相关的知识可以写2 ,3 天。 
首先abort 函数是一个导致消息发生的函数, 引发的消息为 SIGABRT ,说起来就很复杂了吧,什么是消息呢?在 windows 下编程我还从来没有用过类似的东西。事实上 UNIX/Linux 才是消息用的多的地方。 
简而言之,消息是软件中断的一种。 abort 函数和消息的主要(也是最简单的)函数 signal 已经是 ANSI C 标准中的一员了。 
signal 函数也在这里附带讲了算了, MSDN 声明如下: 
Sets interrupt signal handling. 
 
 
void 
  (__cdecl *signal( 
    int sig ,  
    void (__cdecl *func  ) (int [, int ] )))  
    (int);
 
 
 
事实上感觉微软实现消息系统似乎仅仅是为了稍微合乎点ANSI C 的标准,因为在众多的消息中,其只实现了六种,而以下的六种其实都是ANSI. 我没有去查ANSI C 的标准,但是MS 在signal 函数的实现前有注释说明。 
sig  value  
 
Description  
 
 
SIGABRT   
 
Abnormal termination 
 
 
SIGFPE   
 
Floating-point error 
 
 
SIGILL   
 
Illegal instruction 
 
 
SIGINT   
 
CTRL+C signal 
 
 
SIGSEGV   
 
Illegal storage access 
 
 
SIGTERM   
 
Termination request 
 
 
 
SIGABRT 这个由abort 函数引发的消息是其中之一。 
要知道,在一般的UNIX 系统中,消息起码有五十种以上。这也是在windows 中很少有人使用消息,而在Unix/linux 中使用的很多的原因吧。 
另外,MSDN 中虽然MS 明确说明调用abort 函数的返回码是3 ,事实上经过我的实际测试,测试方法为用CreateProcess 运行一个新的用abort 函数结束的进程,然后调用GetExitCodeProcess 函数获得返回值,返回值一直为0. 我也很纳闷,觉得我不对的请自己测试一下,我也希望你们能指出我方式的错误。因为MS 一般不会犯这样的错误,所以我都怀疑自己的正确性。(好啰嗦啊。。。) 
在linux 下( 未有说明仅仅实在我的系统环境中测试) 测试结果为返回134.  
然后,顺便也给出一个signal 函数的用法,这样才能理解abort 函数的作用和消息的作用。 
例子3.2  
#include  <stdlib.h>  
#include  <stdio.h>  
#include  <signal.h>  
  
void  Abort (int  ai ) 
{ 
     printf ("catch the SIGABRT and agrument is %d" , ai );
} 
  
int  main () 
{ 
  
     printf ("Running/n" );
  
     signal (SIGABRT , Abort );
  
     abort ();
  
     printf ("Still Running/n" );
     return  0;
} 
  
此例子在windows 下和linux 下效果一致,都是在调用abort 函数后引发SIGABRT 消息,因为先用signal 捕获了此消息并指定此时调用Abort 函数,所以最后的输出都是 
Running 
catch the SIGABRT and agrument is %d 
有所不同的是,在windows 下%d 为22 ,linux 下为6 ,不知道为什么windows 要特意做的和别人不一样,然后特意声明一个 
#define  SIGABRT_COMPAT    6       
 /* SIGABRT compatible with other platforms, 
same as SIGABRT */  
这一点我比较不解。 
另外,通过对 signal 使用的例子可以看出来,响应的函数的参数实际就是消息定义的值。这样的好处是你可以为所有的消息定义一个函数,然后通过参数来判断到底是哪个消息。就类似与 windows 下可以 SetTimer 多次,而只 OnTimer 一个函数中响应,通过 Timer 的 ID 来判断到底是哪个时间到了。 
再次说明一下,我并不是来说明函数的用法的。。。所以 signal 函数的参数什么的都省略了,请参考 MSDN 或者 <advanced programming in the UNIX 
environment> 一书。 
另外,说明一下的是,假如在 Abort 这个响应函数中提前用 exit 函数退出程序,那么在 linux 下就不会再次触发系统的默认响应,并且程序的退出代码也由 exit 函数指定了。 
在 windows 下,总是会触发系统的默认响应并弹出对话框。。。。。 
另外,试图忽略 SIGABORT 消息(在 signal 函数的第二参数用 SIG_IGN ),我总是没有成功输出过 Still running 的语句,并且总是会触发系统默认响应,无论在 windows 还是 linux 下都是这样,希望有人可以告诉我为什么。 
最后,需要注意的是 Aborted 这个 linux 下的输出实际实在错误流中输出的,比如以上例子编译为 test 程序,通过 echo `./test` 你可以看到,实际只有 Running 输出到标准输出。 
  
实现:  
MS: (删除次要部分) 
void  __cdecl  abort  ( 
         void 
         )
{ 
     _PHNDLR  sigabrt_act  = SIG_DFL ;
  
     if  (__abort_behavior  & _WRITE_ABORT_MSG )
     {
         /* write the 
abort message */ 
         _NMSG_WRITE (_RT_ABORT );
     }
  
................ 
     /* Check if the 
user installed a handler for SIGABRT. 
      * We need to read the user handler 
atomically in the case
      * another thread is aborting while we 
change the signal
      * handler.
      */
     sigabrt_act  
= __get_sigabrt ();
     if  (sigabrt_act  != SIG_DFL )
     {
         raise (SIGABRT );
     }
     _exit (3);
} 
  
先调用 _NMSG_WRITE 函数输出abort 的错误信息,此时即弹出了对话框,无论你怎么设置忽略或者响应函数都没有用。 
当没有忽略此消息时调用 raise (SIGABRT ) 产生消息。 
最后调用_exit 返回错误代码3 作为返回值。这里明明返回了3 ,但是我怎么得到程序的返回值总是0 ?奇了怪了。 
gcc: 
/* We must 
avoid to run in circles.   Therefore we 
remember how far we 
already 
got.   */ 
static  int  stage ; 
  
/* We 
should be prepared for multiple threads trying to run abort.   */ 
__libc_lock_define_initialized_recursive  (static , 
lock ); 
  
  
/* Cause an abnormal program 
termination with core-dump.   */ 
void  abort  (void ) 
{ 
     struct  sigaction  
act ;
     sigset_t  sigs ;
  
     /* First acquire the lock.   */ 
     __libc_lock_lock_recursive  (lock );
  
     /* Now it's for sure we are alone.   But recursive calls are possible.   */ 
  
     /* Unlock SIGABRT.   */ 
     if  (stage  
== 0)
     {
        ++stage ;
        if  (__sigemptyset  
(&sigs ) == 0 &&
            __sigaddset  (&sigs , SIGABRT ) 
== 0)
            __sigprocmask  (SIG_UNBLOCK , &sigs , 
(sigset_t  *) NULL );
     }
  
     /* Flush all streams.   We cannot close them now because the user 
     might have registered a handler for 
SIGABRT.   */
     if  (stage  
== 1)
     {
        ++stage ;
        fflush  (NULL );
     }
  
     /* Send signal which possibly calls a 
user handler.   */ 
     if  (stage  
== 2)
     {
          /* 
This stage is special: we must allow repeated calls of 
        `abort' when a user defined handler for 
SIGABRT is installed.
        This is risky since the `raise' 
implementation might also
        fail but I don't see another 
possibility.   */
        int  save_stage  
= stage ;
  
        stage  = 0;
        __libc_lock_unlock_recursive  
(lock );
  
        raise  (SIGABRT );
  
        __libc_lock_lock_recursive  
(lock );
        stage  = save_stage  + 1;
     }
  
     /* There was a handler installed.   Now remove it.   */ 
     if  (stage  
== 3)
     {
        ++stage ;
        memset  (&act , '/0' , sizeof  (struct  sigaction ));
        act .sa_handler  = SIG_DFL ;
        __sigfillset  (&act .sa_mask );
        act .sa_flags  = 0;
        __sigaction  (SIGABRT , &act , 
NULL );
     }
  
     /* Now close the streams which also 
flushes the output the user 
     defined handler might has produced.   */
     if  (stage  
== 4)
     {
        ++stage ;
        __fcloseall  ();
     }
  
     /* Try again.   */ 
     if  (stage  
== 5)
     {
        ++stage ;
        raise  (SIGABRT );
     }
  
     /* Now try to abort using the system 
specific command.   */ 
     if  (stage  
== 6)
     {
        ++stage ;
        ABORT_INSTRUCTION ;
     }
  
     /* If we can't signal ourselves and the 
abort instruction failed, exit.   */ 
     if  (stage  
== 7)
     {
        ++stage ;
        _exit  (127);
     }
  
     /* If even this fails try to use the 
provided instruction to crash 
     or otherwise make sure we never return.   */
     while  (1)
        /* Try for ever and ever.   */ 
        ABORT_INSTRUCTION ;
} 
  
做的工作差不多,实现手段差好远啊, linux 下多的就是一个文件的 flush 和 close 还有用 static stage 的方式来允许递归的 abort 调用。 glibc 中详尽的注释可帮了我不少忙。以前还真没有见到过类似的用法,今天算是长见识了。说实话,这样一个简单的函数,我并没有完全看懂,可能需要有时间一步一步跟,并创造递归 abort 调用的情况才能很好的理解。 
windows 这点可能是由操作系统自己做了,所以没有在 abort 函数中有体现。 
另外,我怎么测试返回值都是 134...... 但是很明显调用的是 _exit(127) ,原因和 windows 老是返回 0 一样不明。 
效率测试:  
略 
相关函数:  
raise ,signal  
  
个人想法:  
虽然 windows 也包含消息,虽然那 6 个消息是 ANSI 的标准,但是个人推荐,对于可移植的东西来说,最好是不要用消息了,除非你确定只用 windows 的那 6 个消息。即使你只用这六个消息,你都会发现 windows 运行的特性与 linux 不同。不然,对于消息系统来说,要实现 windows 中没有实现的消息不是太容易的事情。。。。。所以,强大的消息系统只能在 windows 中找替代方案了。对于 windows/linux 可移植的东西来说,这也是最大最大的一个缺憾,那就是你不能用太多平台相关的东西,而偏偏很多这样的东西就是这个平台中最好的东西。比如 Windows 的核心对象系统, linux 下的消息系统等等等等,真是缺憾啊。。。 
本来因为有宏嘛,可以在所有类似的系统上再封一层,以达到虽然使用不同的东西也可以保持很好的移植性。但是对于消息系统或者 Windows SEH 这样彻底的破坏程序流程的东西,根本是没有办法通过宏来做到的。宏毕竟不是万能的。 
在实在没有办法的时候,只能把你所封的那一层尽量的调高了(可以到类)。那样,代码量的增加几乎是一倍,除非必要,并不是太值得。(在封装网络模块的时候只能用到) 
在非必要的时候,尽量做到最简单的封装(在简单的函数这一层),这样统一的程序流程和逻辑,也更加容易理解,代码量也小。 
而对于消息系统这样破坏程序流程的东西,甚至想封在一个子类里面,然后使用共同的接口都不是太容易。 
总而言之,非必要,个人认为,可移植程序,少用消息系统。 
  
  
write 
by  九天雁翎 (JTianLing) 
-- www.jtianling.com 
		 阅读全文.... 
   
  
    
    一天一个 C Run-Time Library  函数 (2)  __max & __min 
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
头文件  <stdlib.h>  
msdn:  
Returns the larger of two values. 
 
 
type __max( 
       type   a , 
       type   b   
); 
 
 
 
Returns the smaller of two values. 
 
 
type __min( 
       type   a, 
       type   b   
); 
 
 
 
测试程序:  
#include <stdlib.h> 
#include <stdio.h> 
  
int main( void ) 
{ 
    int a = 10;
    int b = 21;
  
    printf( "The larger of %d and %d is %d/n",   a, b, __max( a, b ) );
    printf( "The smaller of %d and %d is %d/n", a, b, __min( a, b ) );
} 
说明:  
这次的测试程序因为MSDN 中有sample ,就使用了他们原来的程序,起码能够说明问题吧,其实作为一个本意是用来说明移植性的文章系列中,没有samlple 也无所谓的。 
又是两个双前置下划线的函数,事实上C 语言参考和TCPL 中也都没有说明,估计还是属于MS 自己加的。 
gcc 无此函数,鉴于此函数的实用性,自然也需要实现一份。 
对于这么简单的函数也就不多说明了,不然又太过了。 
  
实现:  
MS: 
#define   __max ( a , b )   ((( a ) > ( b )) ? ( a ) : ( b )) 
#define   __min ( a , b )   ((( a ) < ( b )) ? ( a ) : ( b )) 
还是简单的宏,对于一个 C++ 程序员来说,我不是太习惯,可能我属于原教义派,看多了 Bjarne Stroustrup 的书,心中总是对于宏有所排斥,我以前就因为被 windows 一个简单的宏折磨的够呛。那个宏也是关于最大,最小的 , 我在 http://www.jtianling.com/archive/2007/07/06/1680398.aspx 
一文中有所描述。 
简而言之,就是 windows.h 中(实际定义在 windef.h 中,但是 windows.h 包含了 windef.h ,而 windows.h 才是经常包含的文件) 
不知道新的 C 语言中有没有 inline ,实话说,那样要好的多。 
#ifndef   NOMINMAX 
  
#ifndef   max 
#define   max ( a , b )             ((( a ) > ( b )) ? ( a ) : ( b )) 
#endif 
  
#ifndef   min 
#define   min ( a , b )             ((( a ) < ( b )) ? ( a ) : ( b )) 
#endif 
  
#endif    /* NOMINMAX */ 
这样的效果是,所有的 min,max 都会被宏替换,甚至是 
std::numeric_limits<T>::min() 
或者 
#include   "windows.h" 
class   max 
{ 
  
}; 
int   main (  void  ) 
{ 
  
  
     max *  lpmax  =  new   max (); 
     
  
     return  0; 
} 
  
这样的形式都会导致编译通不过,而第一种情况那可是C++ 标准库使用numeric_limits 特性必须的。因为MS 也给出了解决的方式。预先定义一个NOMINMAX 的宏就能解决问题。 
不知道新的 C 语言中有没有 inline ,实话说,那样要好的多。 C 语言运行库中再次实现了最大最小的函数,不过以双前置下划线的方式可以极大的防止宏替换的意外情况。 
用 C 语言就得习惯宏,用 C++ 我常常迫使自己忘记宏,有的时候感觉 C 与 C++ 的区别还是挺大的,特别是 C99 以后。。。。。。。 
对了,对于所有还不习惯 C 语言大面积用宏的兄弟说一句,这样的宏引进了这么多麻烦,其实还是有一个好处的,那就是省略了一次函数的调用。函数的调用在 C /C++ 中开销不算太大,但是在高效率的要求下也不算小,可以看看以前我分析 c++ 函数调用的文章。 
http://www.jtianling.com/archive/2008/06/01/2501238.aspx 
作为 C 语言来说,很多时候自然都是效率之上了。   
  
效率测试:  
略。 
  
相关函数:  
无。 
  
个人想法:  
虽然感觉这两个函数是会很常用到的,但是实际工作中还真没有用过一次。。。说实话,并不是没有这两个函数适用的场合,而是这样的场合自己用 ?: 实现也很简单,所以常常根本想不到还有这样的两个函数可以实现,我更加是没有准备使用 windows.h 中 max,min 宏的想法,很简单就可以做到的事情,为什么要使用以导致移植性的降低了,没有理由。 
  
write by  九天雁翎 (JTianLing) -- www.jtianling.com 
		 阅读全文.... 
   
  
    
    继续为windows/linux通用服务器框架做研究工作,从C语言运行时库开始。
 
最好的可移植编程方式是什么?除了java。。。还有C。。。。,标准C是可以在几乎任何有C语言编译器的机器上运行的,这是lua作者只用标准C开发lua的原因,并谈到了lua可移植性好的理由。他说除了动态链接的模块,他用的几乎都是标准C。
其实说起来移植性最好的可能是C++,C++的标准化工作在今天看来是非常成功的,C++的标准库移植性也是非常的好,可是其实C++中大部分底层的操作还是靠C语言部分来完成,所以研究C++的库好像也没有意义,毕竟我的目的就是考察移植性而已,不是来考察库的用法。。。
 
作为一个服务器的框架,光用标准C好像有点难度。。。比如IOCP,epoll这些最好的服务器模型都是典型的操作系统相关。但是,用C++语言编写时,总会用到C语言的运行时库(在windows下叫CRT -- C Run-Time Library)。并且因为MS为C语言的库做了很多扩展工作,并且将很多POSIX的东西标了前置的下划线,并且都放在这个库中,使得很多时候我自己都不知道哪些是标准库的,哪些是MS扩展的了(都是常查MSDN不翻书的恶果,但是查MSDN的确快了很多)。今天又一次的碰到这个问题。
 
实际程序编写的时候,使用这些库函数,比使用windows API的可移植性(也许仅仅是移植的代价)要好的多。
因为没有直接的类似资料可以查看,所以我下决心,直接一个一个通过实践,决定哪个是windows/linux都可用的,哪些是新扩展,linux下不能用的。仿照很久以前看到某人写的一天一个windows API来写。我就一天一个C Run-Time Library的函数吧:)
 
呵呵,最近刚刚看完了一本bash的书,正好不想再学太多语言语法的东西,想好好的多编点东西,这个正好是个机会。另外。。。个人好像老是计划的多。。。实际做下去的少,希望这个计划能够对自己的计划能力做出考验,然后做一个完整的PDF/CHM,方便大家,也方便自己以后的查看:)
 
另外还可以将MS那些前置的下划线通过宏取消掉,最后还有一个非常非常有必要的事情也可以顺便做了,那就是为linux下的库建立一套asc/Unicode的自适应库(类似TCHAR系统)。
 
顺便,完整性,再贴一次我的开发及测试环境。
windows XP VS2005 VA vimemu boost 1.36 
ubuntu 8.10 gcc version 4.2.4 vim+gdb boost 1.36 
源代码控制统一在 windows XP  中用 VSS.( 个人习惯问题 , 公司用的就是这个 ) 
另外 : 
其他工具包括 .IBM Rational Rose Realtime( 又是习惯问题 , 虽然不是 Realtime 的程序 , 但是因为公司用的是这个 , 个人沿用此习惯 ) 
 
		 阅读全文....