九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

一天一个C Run-Time Library 函数(1) __isascii & __iswascii & __toascii


一天一个C Run-Time Library 函数  __isascii & iswascii & __toascii

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

msdn:

Determines whether a particular character is an ASCII character.

int __isascii(

   int c

);

int iswascii(

   wint_t c

);

测试程序:

#include "stdafx.h"

#include "ctype.h"

#include "locale.h"

#include "stdio.h"

 

void CheckCharAndPrint(char acChar)

{

    if(__isascii(acChar))

    {

       printf("char %c is a ascii char./n",acChar);

    }

    else

    {

        // 此处无法正常输出中文,没有深入研究了

       printf("char %c is not a ascii char./n",acChar);

    }

}

 

void CheckWCharAndPrint(wchar_t awcChar)

{

    if(iswascii(awcChar))

    {

       wprintf(L"wchar %c is a ascii char./n",awcChar);

    }

    else

    {

       setlocale(LC_ALL,"");

       wprintf(L"wchar %c is not a ascii char./n",awcChar);

    }

}

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    char lcC = 'a';

    char lcD = '中';

 

    CheckCharAndPrint(lcC);

    CheckCharAndPrint(lcD);

 

    wchar_t lwcC = L'a';

    wchar_t lwcD = L'中';

 

    CheckWCharAndPrint(lwcC);

    CheckWCharAndPrint(lwcD);

 

    return 0;

}

 

说明:

__isascii是一个比较特殊的函数,因为它以两个前置下划线开头。这在C语言中并不多见。(起码我看到的比较少)

此函数应该不属于标准库函数,《TCPL》中,《C语言参考》中并没有描述,但是gcc中有此函数。也就是说linux下也能正常使用此函数。

iswascii这个__isascii函数的宽字节版本,如同很多宽字节版本的函数一样,这个函数属于MS自己扩的,于是。。linux下无法使用此函数,要使用,只能自己实现罗。

 

实现:

MS:

#define __isascii(_Char)   ( (unsigned)(_Char) < 0x80 )

inline int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); }

gcc:

#define __isascii(c)  (((c) & ~0x7f) == 0)  /* if C is a 7 bit value*/

__isascii都是一个简单的宏。MSiswascii原理和其__isascii都一样,仅仅是一个内联的函数。

微软的实现是依赖于字符小于1280x80),这里还做了一次强转,不是太理解,因为实际char可以直接作为整数来比较,也许仅仅是为了屏蔽warning?

gcc的实现是依赖于字符除低七位外无任何其他值。即先将127(0x7f)取反,再与字符位与。实际就是取得字符c除了低七位以外的值。再比较此值是否为零。

想不到一个这样简单的函数,MS,gcc的实现差别都这么大,相对而言MS的实现自然是比较浅显易懂的,但是gcc用这么复杂的实现,应该有更好的效率。

就分析而言,强转+小于操作 运行时间大于 一次取反一次位与一次等于操作。还真不容易知道谁的效率真的更高。那么就测试一下吧。

效率测试:

#include "jtianling.h"

#define __isasciims(_Char)   ( (unsigned)(_Char) < 0x80 )

#define __isasciigcc(c)  (((c) & ~0x7f) == 0)  /* if C is a 7 bit value*/

 

const int  DEF_TEST_TIMES = 1000000000;

 

void CheckMS(char ac)

{

    double ldTimeLast = jtianling::GetTime();

    for (int i=0; i<DEF_TEST_TIMES ; ++i)

    {

 

       __isasciims(ac);

 

    }

    double ldTimePast = jtianling::GetTime() - ldTimeLast;

 

    printf("__isasciims %c run %d times cost %lf secs./n", ac, DEF_TEST_TIMES, ldTimePast);

}

 

void Checkgcc(char ac)

{

    double ldTimeLast = jtianling::GetTime();

    for (int i=0; i<DEF_TEST_TIMES ; ++i)

    {

 

       __isasciigcc(ac);

 

    }

    double ldTimePast = jtianling::GetTime() - ldTimeLast;

 

 

    printf("__isasciigcc %c run %d times cost %lf secs./n", ac, DEF_TEST_TIMES, ldTimePast);

}

 

int _tmain(int argc, _TCHAR* argv[])

{

    char lc = 'a';

    char lc2 = '中';

    CheckMS(lc);

    Checkgcc(lc);

    CheckMS(lc);

    Checkgcc(lc2);

 

    return 0;

}

至于GetTime函数的意义,请参考我以前写的库,无非就是获取当前时间,不知道也没有关系。你可以用time(NULL)来替代,只不过精度没有这个函数高而已。

实际的测试结果很让人失望,在测试了几乎无数次以后,MSgcc的实现效率都几乎相同,在10亿这个级别,gcc也不过有时快0.1秒而已,而且多次运行,还不是太稳定。看来并不是复杂的实现就一定好。。。

 

相关函数:

msdn:

Converts characters.

int __toascii(

   int c

);

这个函数也是一个双前置下划线的函数,MS,gcc中都有实现。而且在此时,实现都是一样的。

#define __toascii(_Char)   ( (_Char) & 0x7f )

gcc注释到 mask off high bits.

这里和gcc__isascii函数实现的前一部分很像,一个是去除低七位,一个是保留低七位。看了这个以后才知道gcc为什么想到这样实现__isascii了。

 

个人想法:

这两个函数在实际中我从来没有用到过,假如不是我工作范围太窄那就是这两个函数的使用性并不强了,的确,我没有事去把一个值转为ascii?ascii的话就没有意义,不是的话,原来的含义还能保留吗?至于__isascii函数可能还在某些情况下有用吧,只不过我没有用到过,谁有实际中使用此两个函数的代码可以告诉我一下。

 

另外,总结的是,虽然C RuntimeMS也有源码,但是完全没有任何注释。相对而言gcc的注释就算是很丰富和详细了,呵呵,毕竟开源代码就是不一样啊,做来就是给人看的,想想这样分析下去,光是看源代码收获都不会太小。

 

最后。。。。。。。。。。。这样一个最最简单的函数,宏定义的函数。用了我整整一个没有加班的晚上的,晕掉了。当然,有在家里的VS中编程已经不太习惯的因素,但是还是太过了,下次不能这样太过了。。。点到为止就好了,不然这一辈子都分析不完了。

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....

真高兴啊。。。。实际的为开源事业做了点点贡献:),很久前指出的一个lua stdlib的bug得到确认

呵呵,是关于lua stdlib 库的set模块的bug,其实作者好像确认很久了。。。。但是我这段时间一直没有上gmail,所以没有看到。。。作者说,在新版中已经修改此bug...今天下了最新版,发现真是这样:)呵呵,真高兴啊,吸收了开源社区的那么多营养。。。总算有点报答了。。。当然,这仅仅是起步:)

实际流程贴一下。。。满足一下虚荣心。。。其实仅仅是一个很小的很容易发现的bug。。。呵呵,我当时学lua才一两周。。也不可能发现多么难的bug....lol

 

原来的lua stdlib set中某段程序如下:

  1. -- @func propersubset: Find whether one set 
    is
     a proper subset of
  2. -- another
  3. --   @param s, t: sets
  4. -- @returns
  5. --   @param r: true 
    if
     s 
    is
     a proper subset of t, false otherwise
  6. function propersubset (s, t)
  7.   
    return
     subset (s, t) 
    and
     
    not
     subset (t, s)
  8. end
  9. -- @func equal: Find whether two sets are equal
  10. --   @param s, t: sets
  11. -- @returns
  12. --   @param r: true 
    if
     sets are equal, false otherwise
  13. function equal (s, t)
  14.   
    return
     subset (s, t) 
    and
     subset (s, t)
  15. end
  16. -- @head Metamethods 
    for
     sets
  17. -- set + table = union
  18. metatable.__add = union
  19. -- set - table = set difference
  20. metatable.__sub = difference
  21. -- set / table = intersection
  22. metatable.__div = intersection
  23. -- set <= table = subset
  24. metatable.__le = subset

 

于是我发邮件给作者

 

hi all,
Thank you very much for your hard working with the LuaForWindows,I enjoy it so mush.
there is a bug to report as my return.
the set.lua file in the lualibs, 117th line.
source as this code:"return subset (s, t) and subset (s, t)"
it obviously should be "return subset (s,t) and subset(t, s)"
which means they are equal when s is the subset t and t is the subset s.
I hope I'm right and didn't disturb you.
BTW,there is a surprising attribute.
In the set's operations,div(/) mean intersection that is different from custom.
In the custom mul(*) denotes it,just like the <<programming in Lua>> writes in the 13th captial named "metatable and meatmethod"
Thank you for reading my poor Chinglish. lol,I'm Chinese.
Best wishes.
                                                                               your honest
                                                                               JTianLing from jtianling{at}gmail.com

 

 

luaforwindows的作者回信

Andrew Wilson to me, rrt, luaforwindows
show details Sep 3 Reply

 


Thanks for the bug report JTianLing, this particular module comes from
the stdlib library , I'll copy your report of this issue to the
administrator of that project http://luaforge.net/projects/stdlib/
.

Your English is great,  you wouldn't want to even hear my Mandarin.
关心
Andrew Wilson

 

 

呵呵,不知道他这里说关心是什么意思......,惊奇的是。。。。他竟然还真能打中文字。。。。E文系统应该是没有中文输入法的吧。。。。

 

最后lua stdlib的作者回信:

Reuben Thomas to Andrew, me, luaforwindows
show details Sep 4 Reply

Thanks, this is quite correct. I've made a new release with this fix.

 

I see, I had actually forgotten that * is used in Modula-3 in the same way. I am happy to change this so that * is intersection and / is symmetric difference.

Thanks, I've made another release with these changes, and coincidentally fixed set.difference, which was also broken.

 

 

呵呵,最新版的set如下,可见已经修复,并且连那个我称为surprising attribute 的“/”符号表示交集也改了:)

 

  1. -- @func intersection: Find the intersection of two sets
  2. --   @param s, t: sets
  3. -- @returns
  4. --   @param r: set intersection of s 
    and
     t
  5. function intersection (s, t)
  6.   local r = new {}
  7.   
    for
     e 
    in
     elements (s) do
  8.     
    if
     member (t, e) then
  9.       insert (r, e)
  10.     end
  11.   end
  12.   
    return
     r
  13. end
  14. -- @func union: Find the union of two sets
  15. --   @param s, t: sets
  16. -- @returns
  17. --   @param r: set union of s 
    and
     t
  18. function union (s, t)
  19.   local r = new {}
  20.   
    for
     e 
    in
     elements (s) do
  21.     insert (r, e)
  22.   end
  23.   
    for
     e 
    in
     elements (t) do
  24.     insert (r, e)
  25.   end
  26.   
    return
     r
  27. end
  28. -- @func subset: Find whether one set 
    is
     a subset of another
  29. --   @param s, t: sets
  30. -- @returns
  31. --   @param r: true 
    if
     s 
    is
     a subset of t, false otherwise
  32. function subset (s, t)
  33.   
    for
     e 
    in
     elements (s) do
  34.     
    if
     
    not
     member (t, e) then
  35.       
    return
     false
  36.     end
  37.   end
  38.   
    return
     true
  39. end
  40. -- @func propersubset: Find whether one set 
    is
     a proper subset of
  41. -- another
  42. --   @param s, t: sets
  43. -- @returns
  44. --   @param r: true 
    if
     s 
    is
     a proper subset of t, false otherwise
  45. function propersubset (s, t)
  46.   
    return
     subset (s, t) 
    and
     
    not
     subset (t, s)
  47. end
  48. -- @func equal: Find whether two sets are equal
  49. --   @param s, t: sets
  50. -- @returns
  51. --   @param r: true 
    if
     sets are equal, false otherwise
  52. function equal (s, t)
  53.   


    return
     subset (s, t) 
    and
     subset (t, s)
  54. end
  55. -- @head Metamethods 
    for
     sets
  56. -- set + table = union
  57. metatable.__add = union
  58. -- set - table = set difference
  59. metatable.__sub = difference
  60. -- set * table = intersection
  61. metatable.__mul = intersection
  62. -- set / table = symmetric difference
  63. metatable.__div = symmetric_difference
  64. -- set <= table = subset
  65. metatable.__le = subset
  66. -- set < table = proper subset
  67. metatable.__lt = propersubset

 

这虽然是一件芝麻一样的小事,但却是我个人第一次真正的为开源社区做贡献。。。。虽然仅仅是以bug report的形式:)立此存照:)

 

阅读全文....

又是一个新的开始,可以多多实践了,GOD bless China

 最近一段时间学了很多东西,因为时间只有这么多,工作时间太长,空闲时间太少,虽然我几乎用了全部的空闲时间来学习,

但是还是相对而言忽略了实践。

最近看了《lua程序设计》,《python核心编程》,《bash高级编程》,几乎是新学了3门语言(就是python以前还学过一些),

而实际实践的内容无非就是跟着数本简单的敲敲代码,远远不够。。。。接下来应该可以脱离纯粹的语言学习阶段。。。多多实践一下了,这样的阶段应该博客也会多写一些的:)光看书实在没有什么太多好写的:)

 

计划是一边重新学习数据结构。。。(不知道是第几次重新了,没有一次真正的做到看透全书,做完全部习题。。。。)

一般用上述3种语言+c/c++(吃饭的家伙)来完成学习中的突然想法:)比如以前提到的makefile自动生成和linux/windows通用服务器开发库。。。。。

 

 

阅读全文....

记下教训,关于SHFileOperation的使用,命令行程序的使用

假如你也一直开发的都是windows,linux下都能跑的程序,关于目录的使用你肯定就和我一样统一了,都是用"/"来表示。道理很简单,因为linux不支持"/"而windows支持"/",一直以来都是这样,linux原生的"/"使用自然没有任何问题,windows下的fopen,CreateFile,OpenFile,CreateProcess等等使用的也不是一次两次了,用的也都没有问题。当然,今天,问题来了,一碰到就调试的人郁闷的要死。

 

关于SHFileOperation的。此该死的函数,没有错误返回代码,只能知道执行失败,通过GetLastError返回的甚至可能是在MSDN中SystemError说明以外的数值。于是,噩梦开始了。当我用按照习惯的使用"/"来表示目录,并测试代码,在目录只有一层的时候是可以成功的,即类似E:/data的目录执行没有问题。但目录为很多层的时候,SHFileOperation竟然也有时能够成功,但是有时却会失败,输入参数我一再验证没有问题。(输入参数以双零结尾也是需要注意的),直到我崩溃。准备直接用CreateProcess调用copy /y ,del 等命令来完成任务的时候,才想起来"/"在dos(windows所谓的的shell吧)中用来表示参数。。。。用"/"表示目录来调用dos命令总是会失败的。。。。。。。才联想到SH的名字。。。SHell啊。。。。。一切都明白了。。。。需要说明的是,这一点MSDN中没有任何说明,并且,即使我使用"/"来表示目录并调用SHFileOperation竟然还有成功的时候。。。。更多时候也不是完全失败,而且进行了一半。。。。。。。太没有天理了,还没有ErrorCode。。。。。。。

 

另外,今天在寻找一些解压的库,用来完成监控系统中的更新操作。找了一下午,zlib,7-zip的支持库等,找了一圈,不是不支持rar就是用法不明,或者不支持linux,最后发现都不适合,而unrar这个命令行工具其实就完成可以完成任务。。。。。。。无非就是一个熟悉的CreateProcess而已,感叹不已,想起来我以前学习的时候还特意怀旧般的为DOS命令写了一系列文章,到了工程应用的时候竟然都忘了。。。。其实有的时候用命令行提供给你的工具,比找个库要简单的多。。。。

阅读全文....

vim真是越用越好用,贴一下配置文件.vimrc

 一方面自己在别的地方可以看到:)

其实想想以前,vim的配置无非就是看看别人的很长的配置文件,自己照着copy一下,现在基本上形成了自己的习惯了,有什么需要的自己加入快捷键了,特别是以“,”(逗号)开始的leader使用起来非常的方便,虽然其实是牺牲了一个重复反向查找的功能。。。。但是实际中,我没有有过用到","这样奇怪的需求,所以覆盖了也不怎么可惜。

可惜的是发上来的文件没有语法高亮。。。。。。。。。。

 

let mapleader=","
set encoding=utf-8
set ambiwidth=double
set nocompatible
set hls
set nu
set ai
colors desert
syntax on
set sw=4
set ts=4
"set autocmd
set smarttab
set whichwrap+=h,l,~,b,s,<,>,[,]
set helplang=cn
set ruler
set showcmd
filetype plugin indent on
set nomagic
set mouse=a
set cmdheight=2
set backspace=eol,start,indent
set showmatch
set wildmenu

"-----------------------------------------------------------
" for snippetsEmu_key but it's snippet file is not created
"-----------------------------------------------------------
let g:snippetsEmu_key = "<S-Tab>"

"-----------------------------------------------------------
" folding
"-----------------------------------------------------------
"enable folding, i find it very useful
set nofen
set fdl=0
set lbr

set si
set wrap

"-----------------------------------------------------------
" some key I maped and liked
"-----------------------------------------------------------
" I like use <space> <bs> <cr> key in normal mode
nmap <space> i<space><esc>l
nmap <bs> i<bs><esc>l
nmap <cr> i<cr><esc>

" sometimes use this to p sth in new line
nmap <leader>o o<esc>p
nmap <leader>O O<esc>p

" one key to save even in insert mode
nmap <f2> :w<cr>
imap <f2> <esc>:w<cr>a

" select all :) like microsoft's CTRL-A
nmap <leader>a ggVG

"-----------------------------------------------------------
" for favarite c/c++
"-----------------------------------------------------------
" normal mode
autocmd filetype c map<silent><buffer> <f6> :w<cr>:make<cr>:cw<cr>
autocmd filetype cpp map<silent><buffer> <f6> :w<cr>:make<cr>:cw<cr>

"-----------------------------------------------------------
" For special script file type
" I only need to use python,lua,sh and surely only know these
"-----------------------------------------------------------
" normal mode
autocmd filetype python map<buffer> <f5> :!clear<cr>:w<cr>:!python %<cr>
autocmd filetype lua map<buffer> <f5> :!clear<cr>:w<cr>:!lua %<cr>
autocmd filetype sh map<buffer> <f5> :!clear<cr>:w<cr>:!./%<cr>
" insert mode
autocmd filetype python imap<buffer> <f5> <esc>:!clear<cr>:w<cr>:!python %<cr>
autocmd filetype lua imap<buffer> <f5> <esc>:!clear<cr>:w<cr>:!lua %<cr>
autocmd filetype sh imap<buffer> <f5> <esc>:!clear<cr>:w<cr>:!./%<cr>
"-----------------------------------------------------------

"-----------------------------------------------------------
" taglist
"-----------------------------------------------------------
let Tlist_Exit_OnlyWindow = 1
let Tlist_Use_Right_Window = 1
let Tlist_File_Fold_Auto_Close = 1
map <leader>to :Tlist<cr>

"-----------------------------------------------------------
" for quickfix
"-----------------------------------------------------------
nmap <silent> <leader>n :cn<cr>
nmap <silent> <leader>p :cp<cr>

"-----------------------------------------------------------
" for vimgdb
"-----------------------------------------------------------
source ~/vimrc/gdb_mappings.vim

"-----------------------------------------------------------
" WinManager Setting
"-----------------------------------------------------------
let g:winManagerWindowLayout = "FileExplorer"
let g:winManagerWidth = 30
let g:defaultExplorer = 0
nmap <silent> <leader>wm :WMToggle<CR>

"-----------------------------------------------------------
" for A.vim a useful plugin
"-----------------------------------------------------------
nmap <leader>aa :A<cr>
nmap <leader>as :AS<cr>
nmap <leader>av :AV<cr>

"-----------------------------------------------------------
" for MiniBufExplorer and buffer opearate
"-----------------------------------------------------------
nmap <leader>1 :b 1<CR>
nmap <leader>2 :b 2<CR>
nmap <leader>3 :b 3<CR>
nmap <leader>4 :b 4<CR>
nmap <leader>5 :b 5<CR>
nmap <leader>6 :b 6<CR>
nmap <leader>7 :b 7<CR>
nmap <leader>8 :b 8<CR>
nmap <leader>9 :b 9<CR>
nmap <leader>0 :b 10<CR>

阅读全文....

linux/windows库准备工作

既然准备尝试在linux下开发程序,一些准备工作是必须的,比如makefile,shell,等等,目前学习了一下makefile文件的写法,的确大有学问,趁着这个学习的机会,翻看了一下公司目前的通用makefile,发现其实写的并不是很好,这点到时候和总监去说说,虽然改起来方便,但是实际上对于文件的依赖性处理的有问题。

另外,看了一下automake的东西,发现那东西只适合程序的发布时使用,不适合开发的时候使用。

于是,自己想写一个开发用的make文件自动生成工具,也有些思路,顺便熟悉一下这段时间囫囵吞枣式的语言学习,
以前就有想法,将数据结构的课程习题全部用C++,Python两种语言来完成,当时的确是水平不济,加不想用太多时间在python上。现在不一样了,其实作为一个游戏开发人员,脚本语言的掌握是很必要的:)另外,linux下的shell(bash)编程也挺有意思和用途。

所以,和那时比较,现在的野心也更大了,我决定用bash shell,C++,lua,python四种语言来实现这个适合工程用的自动make文件生成:)

希望能够顺利,这个工作不大,是锻炼语言的好机会。

阅读全文....

lua table输出函数(可以输出嵌套表格)

function PrintTable(o, f, b)
    if type(f) ~= "function" and f ~= nil then
        error("expected second argument %s is a function", tostring(f))
    end
    if type(b) ~= "boolean" and b ~= nil then
        error("expected third argument %s is a boolean", tostring(b))
    end
    p = f or io.write
    b = b or false
    if type(o) == "number" or
        type(o) == "function" or
        type(o) == "boolean" or
        type(o) == "nil" then
        p(tostring(o))
    elseif type(o) == "string" then
        p(string.format("%q",o))
    elseif type(o) == "table" then
        p("{/n")
        for k,v in pairs(o) do
            if b then
                p("[")
            end

            PrintTable(k, p, b)

            if b then
                p("]")
            end

            p(" = ")
            PrintTable(v, p, b)
            p(",/n")
        end
        p("}")

    end
end

最近因为工作需要,学习了lua,呵呵,挺有意思了,甚至让我萌生了回去继续学习以前学过一下的python.
因为常用vim编写lua,调试不是太方便,所以根据programming in lua写了上面这个函数,用起来还算方便,当
需要输出到文件的时候就指定第二参数,或者通过io.output改变io.write的行为.第三参数是指定需要输出
到文件并能重新读出来时的[]号的,具体原因就不多讲了,看看programming in lua 就知道了.

下面是个示例:
a = {[{100, 200}] = { 300, 400}, 200, { 300, 500}, abc = "abc"}
PrintTable(a, io.write, true)

输出结果如下:
{
[1] = 200,
[2] = {
[1] = 300,
[2] = 500,
},
[{
[1] = 100,
[2] = 200,
}] = {
[1] = 300,
[2] = 400,
},
["abc"] = "abc",
}

其实还是合法的lua语句,可以用来作为序列化语句,或者配置文件.没有经过严格测试,仅作为抛砖引玉.
对于新手,提示一下,可以通过在此函数前加上module("PrintTable", package.seeall),并将此文件保存在
类似lualibs的库目录,然后就可以通过在你自己的程序中用require "PrintTable"来使用此函数了.

阅读全文....

读windows核心编程,结构化异常部分,理解摘要

23:

结束处理程序:

 

__try{}

__finally{}块语句,能保证在运行完__try的语句后能调用__finally{}块中的语句,就算是提前的return,break,continue,goto, 内存访问违规等都可以保证,但是当调用ExitThreadExitProcess,将立即结束线程或进程,由于调用TerminateThreadTerminateProcess而结束线程或进程,不会执行__finally块中的代码.

但是在__try块过早退出时,会导致局部展开,影响效率,应该尽量放在外面.

当碰到一些的确需要在块内部使用return,可以先用__leave关键字代替,以直接从__try块转到__finally,并在最后调用return语句返回,这样避免了局部展开,提高了效率,但是额外的代价是需要加入一个表示函数成功完成的bool变量.

可以在__finally块中调用AbnormalTermination内部函数确定是否是非正常退出__try,发生局部展开和内存访问违规等都算在内,此时返回true,当自然进入__finally块时,此函数返回false.可以通过这种方式决定到底在__finally块中执行什么代码.不能在其它地方调用.

此结束处理程序的作用:

简化错误处理,提高程序可读性,使代码更容易维护,使用得当具有很小的系统开销.

 

24:

异常处理程序:

 

__try{}

__except(){}

__try块中使用return,break,continue,goto语句不会带来额外开销.

__try{}

__except(EXCEPTION_EXECUTE_HANDLER){}

发生异常时,执行完__except块中的代码后,从其后的下一条语句开始执行.

__try{}

__except(EXCEPTION_CONTINUE_EXCUTION){}

发生异常时,执行完__except块中的代码后,重新从导致异常的原指令开始执行.

__try{}

__except(EXCEPTION_CONTINUE_SEARCH){}

发生异常时,不执行__except块中的代码,直接查找上一个匹配的__except块执行.

可以在_except块中和条件中调用GetExceptionCode()函数来确定到底是什么异常,不能在其它地方调用.

 

当一个异常发生时,操作系统向引起异常的线程的栈里压入三个结构,

EXCEPTION_RECORD, EXCEPTION_POINTERS, CONTEXT ,其中EXCEPTION_POINTERS就是两个指针成员,指向压入栈中的其它两个成员, breakpadexinfo结构就是这个指针的类型.并且成员和含义完全一样.

 

GetExceptionInformation函数只能在异常过滤器中使用,也就是__except的条件中调用.块中都不能使用.但是可以想办法在异常过滤器中就将结果保存下来,放到以后使用.

 

软件异常:

可以由void RaiseException(

  DWORD dwExceptionCode,

  DWORD dwExceptionFlags,

  DWORD nNumberOfArguments,

  const ULONG_PTR* lpArguments

);

引发.但是dwExceptionCode要遵循winerror.h文件中定义的一样的规则.

第二参数为是否允许异常过滤器返回EXCEPTION_CONTINUE_EXCUTION的标志位,当设为0为允许,设为EXCEPTION_NONCONTINUABLE为不允许,当不允许的时候,异常过滤器返回EXCEPTION_CONTINUE_EXCUTION,会引发新的异常EXCEPTION_CONTINUE_EXCEPTION.

在异常的时候发生新的异常,旧的异常消息会保留在EXCEPTION_RECORDExceptionRecord链表中.

 

25:

未处理异常和c++异常

Windows内部启动线程的方式也使用了SHE框架,当一个线程发生异常的时候,首先通过UnhandledExceptionFilter(GetExceptionInformation())处理,默认方式为弹出熟悉的报错对话框,close后通过ExitProcess(GetExceptionCode())退出,debug即传递合适的参数CreateProcess开启新的调试进程来调试异常的程序.

通过以SEM_NOGPFAULTERRORBOX为参数调用SetErrorModel函数,可以防止显示异常消息框.通过对每个线程和主线程的try-except块包装,可以自己处理每一个异常.而不调用默认的UnhandledExceptionFilter.windows还提供SetUnhandledExceptionFilter函数来定义某个进程中所有的线程发生异常时调用的异常过滤器.此函数的参数为用户自定义的异常过滤器的指针.

VC,C++的异常实际用SHE来实现,并且SHEC++异常有更多功能,比如可以从一个硬件错误中恢复过来.可以在一个程序不同函数中同时使用两套异常系统,但是不能混合使用,也不能在一个函数中使用两套系统.

 

阅读全文....