曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 3986|回复: 0

[异常处理] try 与 except

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
发表于 2014-1-22 12:04:48 | 显示全部楼层 |阅读模式
在遇到如“对未正确初始化或计算过的指针解引用”,“数组下标超过边界”,“除数为 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 体系结构中,当异常发生时异常处理程序在堆栈中的位置如何定位。一旦异常处理程序块完成,控制权就传递给异常块之后的下一条语句,除非在处理程序中还有其它的控制流语句。



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;
}


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-3-29 19:41 , Processed in 0.095181 second(s), 28 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表