如何使用C断言让代码更安全?
阅读杂项。与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 条件(来自第一个示例)吗?
正确的策略是什么(如果有的话)?
Reading misc. tutorials related to SDL development I've found two different examples, doing the same thing, but in a different manner. I was wondering which of the two are you considering to be correct, judging from the perspective of code "security" and maintainability .
In the first example the programmer isn't using assert at all, but the code looks OK (at least for my eye):
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);
}
In the second example the programmer [other] is using a different approach, something like (the code isn't exactly copy-paste):
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);
}
Is it OK to "substitute" in the if conditions (from the first example) with asserts like in the second example ?
What's the right strategy (if there's any) ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
进行这种替换是不行的。第二个示例是错误的,因为在非调试版本中,assert(x) 扩展为无内容(当 NDEBUG 时) > 已定义)。这意味着上面
assert
中的指针检查已从发布版本的代码中删除。这绝对是错误的。那么,什么时候应该使用
assert
呢?它对于记录和调试很有用。在某种程度上,您是在说,“我确信这个条件是正确的,并将其作为断言
放在这里,以在调试期间捕获错误代码,并将该条件记录给读者代码”。因此,这两个示例之间存在很大差异。对于检查
malloc
的返回值之类的事情,assert
是错误的,因为不能保证它们会返回非NULL
,正如我所言上面已经提到,assert(x)
的意思是“我完全确定x
为真”,而不仅仅是“如果x
不为真,这很糟糕”。为此,可以使用 if(x) good(); else bad(); 控制。SDL_Init
和SDL_SetVideoMode
可以分别返回-1
和NULL
。It is not OK to do this substitution. The second example is wrong, because
assert(x)
gets expanded to nothing in non-debug builds (whenNDEBUG
is defined). This implies that the pointer checks inassert
above are removed from the code in release builds. That is definitely wrong.So, when should one use
assert
? It is useful for documenting and debugging. In a way, you're saying, "I am sure that this condition is true, and am putting it here as anassert
to catch bad code during debugging, and to document the condition to the readers of the code".So, there is a BIG difference between the two examples. For things like checking the return value of
malloc
,assert
is wrong because there is no guarantee that they will return non-NULL
, and as I have mentioned above,assert(x)
means "I am completely surex
is true", and not just "Ifx
is not true, it is bad". For this, one usesif(x) good(); else bad();
control.SDL_Init
andSDL_SetVideoMode
can return-1
andNULL
respectively.当事情以意想不到的方式出现问题时,应该使用
assert
。通常,如果断言失败,则意味着程序中存在错误。断言不用于可能发生的预期错误(即无法打开文件、无法初始化某些内容等等)。在您提供的示例中,
assert
似乎不是最合乎逻辑的解决方案。当程序无法初始化 SDL 时,以结构化方式告诉用户比抛出断言(这可能会在某些系统上导致段错误)更有意义。assert
should be used when things go awry, in an unexpected way. Usually if an assertion fails, it means there is a bug in the program. Assertions are not used for expected errors that can just happen (i.e. failed to open a file, failed to initialize something, and so on).In the example you presented,
assert
doesn't seem like the most logical solution. When the program failed to init SDL it makes more sense to tell it to the user in a structured way than to throw an assertion (which can just cause a seg-fault on some systems).Assert 语句通常仅用于调试构建,并且会停止程序并通常允许您进入调试器。在发布版本中仍然检查错误条件可能是有意义的。一种简单的方法可能是这样的:
Assert statements are typically used only for debug builds and will halt the program and often allow you to break into a debugger. It probably makes sense in the release build to still check for error conditions. One simple way might be like this:
我使用断言来记录前置条件和后置条件。
(识别功能的意图)
就像..
I use assertion for documenting preconditions and postconditions.
(identifying intention of the function)
like..