曲径通幽论坛

标题: [异常处理] try 与 except [打印本页]

作者: beyes    时间: 2014-1-22 12:04
标题: [异常处理] try 与 except
在遇到如“对未正确初始化或计算过的指针解引用”,“数组下标超过边界”,“除数为 0,计算溢出”这些错误(异常)时,我们需要从错误中恢复,而不是终止程序。

SEH (结构化异常处理)使用 "try" 与 "except" 块来捕捉与处理产生的异常,代码框架如下:
__try {
    /* 要被监视的代码块 */
}
__except (filter_expression) {
   /* 异常处理块 */
}

注意:__try 和 __except 是 C 编译器能识别的关键字,并不是标准 C 的一部分。

如果在 __try 块中的代码发生了异常,操作系统就会将控制权转给位于 __except 中的异常处理程序。

filter_expression 称为“过滤表达式”,当异常发生后,它会被计算,它的值决定接下来要做的动作。这个表达式通常是文字常量、一个条件表达式 或者是对 过滤函数的调用;不论是什么情况,该表达式都应该返回下面 3 个值中的一个:

1. EXCEPTION_EXECUTE_HANDLER
当为此值时,采取通常的做法,即去执行异常处理程序。实际上,异常也可以发生在嵌入 try 块中的另一个代码块里,在这种情况下,运行时支持“栈解退”(unwind)操作。如果异常发生在 try 块中的一个函数调用时,如果该函数没有合适的异常处理程序,也会发生同样的情况。下图展示了在 X86 体系结构中,当异常发生时异常处理程序在堆栈中的位置如何定位。一旦异常处理程序块完成,控制权就传递给异常块之后的下一条语句,除非在处理程序中还有其它的控制流语句。
[attach]2436[/attach]


2. EXCEPTION_CONTINUE_SEARCH
Windows 忽略本异常处理程序,并在封闭块中寻找其它的异常处理程序,直到找到一个合适的。

3. EXCEPTION_CONTINUE_EXECUTION
Windows 立即将控制权返回给异常发生点。在某些异常发生后是不可能继续执行的,即使不是这样,也不建议这么做,若非做不可,系统会立即生成另一个异常。

测试程序:
[C] 纯文本查看 复制代码
// toupper.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
        setlocale(LC_ALL, "chs");

        HANDLE  hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;
        DWORD nXfer, iFile, j;
        TCHAR outFileName[256] = _T(""), *pBuffer = NULL;
        OVERLAPPED ov = { 0, 0, 0, 0, NULL };
        LARGE_INTEGER fSize;
       

        if (argc <= 1) {
                _ftprintf(stderr, _T("Usage: toupper files\n"));
                exit(EXIT_FAILURE);
        }

        for (iFile = 1; iFile < (unsigned int)argc; iFile++) __try { /* Exception block */

                if (_tcslen(argv[iFile]) > 250) {
                        _ftprintf(stderr, _T("文件名太长!\n"));
                        exit(EXIT_FAILURE);
                }

                _stprintf(outFileName, _T("UC_%s"), argv[iFile]);

                __try {

                        hIn = CreateFile(argv[iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

                        if (hIn == INVALID_HANDLE_VALUE){
                                _ftprintf(stderr, _T("读文件失败!\n"));
                                exit(EXIT_FAILURE);
                        }
                        if (!GetFileSizeEx(hIn, &fSize) || fSize.HighPart > 0) {
                                _ftprintf(stderr, _T("Sorry,该文件对本程序来说太大了!\n"));
                                exit(EXIT_FAILURE);
                        }

                        hOut = CreateFile(outFileName, GENERIC_READ | GENERIC_WRITE,
                                0, NULL, CREATE_NEW, 0, NULL);
                        if (hOut == INVALID_HANDLE_VALUE) {
                                _ftprintf(stderr, _T("转换输出失败!\n"));
                                exit(EXIT_FAILURE);
                        }

                        /* 为转换分配缓存 */
                        pBuffer = (TCHAR *)malloc(fSize.LowPart);
                        if (pBuffer == NULL) {
                                _ftprintf(stderr, _T("内存分配失败!\n"));
                                exit(EXIT_FAILURE);
                        }

                        /*读入数据并进行转换,最后写到输出文件*/
                        /*完成后释放资源,然后处理下一个文件*/

                        if (!ReadFile(hIn, pBuffer, fSize.LowPart, &nXfer, NULL) || (nXfer != fSize.LowPart)) {
                                _ftprintf(stderr, _T("读文件错误!\n"));
                                exit(EXIT_FAILURE);
                        }

                        for (j = 0; j < fSize.LowPart; j++) /* 转换数据 */
                                if (isalpha(pBuffer[j]))
                                        pBuffer[j] = toupper(pBuffer[j]);

                        if (!WriteFile(hOut, pBuffer, fSize.LowPart, &nXfer, NULL) || (nXfer != fSize.LowPart)){
                                _ftprintf(stderr, _T("写文件错误!\n"));
                                exit(EXIT_FAILURE);
                        }
                } __finally { /* File handles are always closed */
                        /* memory freed, and handles and pointer reinitialized. */
                        if (pBuffer != NULL) free(pBuffer); pBuffer = NULL;
                        if (hIn != INVALID_HANDLE_VALUE) {
                                CloseHandle(hIn);
                                hIn = INVALID_HANDLE_VALUE;
                        }
                        if (hOut != INVALID_HANDLE_VALUE) {
                                CloseHandle(hOut);
                                hOut = INVALID_HANDLE_VALUE;
                        }
                        _tcscpy(outFileName, _T(""));
                }
        }
       
        __except (EXCEPTION_EXECUTE_HANDLER) {
                _tprintf(_T("异常发生,处理文件错误 %s\n"), argv[iFile]);
                DeleteFile(outFileName);
        }
        _tprintf(_T("已经转换了所有文件!\n"));
        return 0;
}


该程序可以将命令行参数中指定的文件进行大小写转换。如果在处理文件发生错误时,会打印“异常发生,处理文件错误”的提示,以及删除掉生成的转换文件。






欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2