如何使用C断言使代码更安全?

读misc。 与SDL开发相关的教程我发现了两个不同的例子,做同样的事情,但是以不同的方式。 从代码“安全性”和可维护性的角度来看,我想知道你认为哪两个是正确的。

在第一个例子中,程序员根本没有使用断言,但代码看起来还不错(至少在我看来):

int main(){ SDL_Surface *screen; /** Initialize SDL */ if(SDL_Init(SDL_INIT_VIDEO)!=0){ fprintf(stderr,"Unable to initialize SDL: %s",SDL_GetError()); } atexit(SDL_Quit); /** Sets video mode */ screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE); if(screen==NULL){ fprintf(stderr,"Unable to set video mode: %s",SDL_GetError()); } return (0); } 

在第二个例子中,程序员[其他]正在使用不同的方法,例如(代码不完全是复制粘贴):

 int main(){ SDL_Surface* screen; /** Initialize SDL */ assert(SDL_Init(SDL_INIT_VIDEO)==0); atexit(SDL_Quit); /** Sets video mode */ screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE); assert(screen!=NULL); return (0); } 

是否可以在if条件(从第一个示例)中“替换”与第二个示例中的断言一样?

什么是正确的策略(如果有的话)?

做替换是不行的。 第二个例子是错误的 ,因为assert(x)在非调试版本中扩展为空(当定义了NDEBUG时)。 这意味着上面assert中的指针检查将从发布版本中的代码中删除。 这绝对是错误的。

那么,何时应该使用assert ? 它对于记录调试很有用。 在某种程度上,你说,“我确信这种情况是正确的,我把它作为一个assert来在调试过程中捕获错误的代码,并将条件记录给代码的读者”。

因此,两个例子之间存在巨大差异。 对于像检查malloc的返回值这样的事情, assert是错误的,因为不能保证它们将返回非NULL ,并且如上所述, assert(x)表示“我完全确定x是真的”,而不是只是“如果x不是真的,那就太糟糕了”。 为此,使用if(x) good(); else bad(); if(x) good(); else bad(); 控制。

SDL_InitSDL_SetVideoMode可以分别返回-1NULL

当事情出错时,应以意想不到的方式使用assert 。 通常,如果断言失败,则表示程序中存在错误。 断言不会用于可能发生的预期错误(即无法打开文件,无法初始化某些内容,等等)。

在您提供的示例中, assert似乎不是最合理的解决方案。 当程序无法初始化SDL时,更有意义的是以结构化方式告诉用户而不是抛出断言(这可能只会在某些系统上导致seg-fault)。

断言语句通常仅用于调试版本,并将暂停程序,并且通常允许您进入调试器。 在发布版本中,仍然可以检查错误情况。 一种简单的方法可能是这样的:

 assert( condition ); if ( !condition ) handle error; 

我使用断言来记录前置条件和后置条件。 (确定function的意图)

喜欢..

 double positive_division(double dividend, double divisor) { //preconditions ASSERT(dividend>=0); ASSERT(divisor >0); double quotient = dividend/divisor; //postconditions ASSERT(quotient>=0); return quotient; }