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

发布于 2024-08-16 14:18:33 字数 1046 浏览 2 评论 0原文

阅读杂项。与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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

柠檬色的秋千 2024-08-23 14:18:33

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

那么,什么时候应该使用 assert 呢?它对于记录调试很有用。在某种程度上,您是在说,“我确信这个条件是正确的,并将其作为断言放在这里,以在调试期间捕获错误代码,并将该条件记录给读者代码”。

因此,这两个示例之间存在很大差异。对于检查 malloc 的返回值之类的事情,assert 是错误的,因为不能保证它们会返回非 NULL,正如我所言上面已经提到,assert(x) 的意思是“我完全确定 x 为真”,而不仅仅是“如果 x 不为真,这很糟糕”。为此,可以使用 if(x) good(); else bad(); 控制。

SDL_InitSDL_SetVideoMode 可以分别返回 -1NULL

It is not OK to do this substitution. The second example is wrong, because assert(x) gets expanded to nothing in non-debug builds (when NDEBUG is defined). This implies that the pointer checks in assert 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 an assert 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 sure x is true", and not just "If x is not true, it is bad". For this, one uses if(x) good(); else bad(); control.

SDL_Init and SDL_SetVideoMode can return -1 and NULL respectively.

柳若烟 2024-08-23 14:18:33

当事情以意想不到的方式出现问题时,应该使用 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).

盗梦空间 2024-08-23 14:18:33

Assert 语句通常仅用于调试构建,并且会停止程序并通常允许您进入调试器。在发布版本中仍然检查错误条件可能是有意义的。一种简单的方法可能是这样的:

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

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:

assert( condition );
if ( !condition )
    handle error;
等待圉鍢 2024-08-23 14:18:33

我使用断言来记录前置条件和后置条件。
(识别功能的意图)

就像..

double positive_division(double dividend, double divisor)
{
    //preconditions
    ASSERT(dividend>=0);
    ASSERT(divisor >0);

    double quotient = dividend/divisor;

    //postconditions    
    ASSERT(quotient>=0);
    return quotient;
}

I use assertion for documenting preconditions and postconditions.
(identifying intention of the function)

like..

double positive_division(double dividend, double divisor)
{
    //preconditions
    ASSERT(dividend>=0);
    ASSERT(divisor >0);

    double quotient = dividend/divisor;

    //postconditions    
    ASSERT(quotient>=0);
    return quotient;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文