文号
838817
阅读
22446
回复
3
收藏
4
C语言多步错误处理最好还是使用do-while(0)-break
2017/08/27
IP:四川

使用嵌套的if块会嵌套过深以至于难以整理

使用平行的if块对C++/C99变量初始化不友好,【C++/C99变量初始化也是有效代码】,放if块里边限制生存期,放if块外面不受if块控制

使用【if (失败) goto 清理;】不美观,C++/C99变量初始化会有被跳过的警告

所以还是使用do-while(0)-break比较好

需要清理的资源变量声明;
do
{
    不需要清理的变量声明;
    可能失败的操作;
    if (失败) break;
    不需要清理的变量声明;
    可能失败的操作;
    if (失败) break;
    // ...
}while(0);
if (变量1需要清理)
    清理变量1;
if (变量2需要清理)
    清理变量2;
// ...
[ 修改于9年3个月前 - 2017/08/27 03:47:11 ]
9年3个月前IP:江苏
838971
1楼
强行套一层啊。。。
引用
评论
9年3个月前修改于 9年3个月前IP:湖北
839288
2楼
这是Visual Studio 2010(Visual C++ 10.0)中MFC源程序的WINMAIN.CPP文件代码(渲染代码我目前做不好,如果有经验者能帮助一下最好):

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);

int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();

// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;

// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;

// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();

InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif

AfxWinTerm();
return nReturnCode;
}

微软自己都是goto用得不亦乐乎,用goto也没什么不可以,特别是在要做错误后集中清理的情况下,如果没有try...catch...finally这样的控制结构,goto反而可能是一种很清晰简单的做法。

笔者从非结构化的BASIC语言(就是那种老式带行号的)开始编程,一直保留着用goto的习惯,goto并不是编程中的绝对禁忌。

任何时候,都是人选择合适的编程语言和语言特性使用,不是人被编程语言牵着鼻子走。
引用
评论
acmilan作者
9年3个月前修改于 9年3个月前IP:四川
839294
3楼

不违背语言逻辑的做法都是可行的。。。

像是这种情况,就不能用goto。

#include <windows.h>
#include <tchar.h>
#include <string>
#include <iostream>
using namespace std;
int _tmain(int argc, TCHAR **argv)
{
	if (argc >= 1) goto b;
	int i = 1; // warning & assert fail
	//string s = "aaa"; // compile error
b:
	cout << i << endl;
	return 0;
}
</iostream></string></tchar.h></windows.h>

微软那个可以用goto是因为变量声明和初始化都写在函数开头附近,不存在被跳过的问题。

一般来说,如果你习惯于C89风格的那种变量声明全部写在开头的做法,完全可以随意使用goto。但是如果你习惯于ISO C++风格的那种变量声明写在程序中间的做法,就应该考虑一下其它写法。比如你如果觉得do-while(0)-break太拽,完全可以换一种写法。

	需要清理的资源变量声明;
	{
		不需要清理的变量声明;
		可能失败的操作;
		if (失败) goto 清理;
		// ...
	}
清理:
	if (变量1需要清理)
		清理变量1;
	// ...
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的