Practical usage of setjmp and longjmp in C

前端 未结 8 1744
忘了有多久
忘了有多久 2020-11-28 01:48

Can anyone explain me where exactly setjmp() and longjmp() functions can be used practically in embedded programming? I know that these are for err

8条回答
  •  渐次进展
    2020-11-28 02:21

    setjmp and longjmp can be very useful in unit testing.

    Suppose we want to test the following module:

    #include 
    
    int my_div(int x, int y)
    {
        if (y==0) exit(2);
        return x/y;
    }
    

    Normally, if the function to test calls another function, you can declare a stub function for it to call that will mimic what the actual function does to test certain flows. In this case however, the function calls exit which does not return. The stub needs to somehow emulate this behavior. setjmp and longjmp can do that for you.

    To test this function, we can create the following test program:

    #include 
    #include 
    #include 
    #include 
    
    // redefine assert to set a boolean flag
    #ifdef assert
    #undef assert
    #endif
    #define assert(x) (rslt = rslt && (x))
    
    // the function to test
    int my_div(int x, int y);
    
    // main result return code used by redefined assert
    static int rslt;
    
    // variables controling stub functions
    static int expected_code;
    static int should_exit;
    static jmp_buf jump_env;
    
    // test suite main variables
    static int done;
    static int num_tests;
    static int tests_passed;
    
    //  utility function
    void TestStart(char *name)
    {
        num_tests++;
        rslt = 1;
        printf("-- Testing %s ... ",name);
    }
    
    //  utility function
    void TestEnd()
    {
        if (rslt) tests_passed++;
        printf("%s\n", rslt ? "success" : "fail");
    }
    
    // stub function
    void exit(int code)
    {
        if (!done)
        {
            assert(should_exit==1);
            assert(expected_code==code);
            longjmp(jump_env, 1);
        }
        else
        {
            _exit(code);
        }
    }
    
    // test case
    void test_normal()
    {
        int jmp_rval;
        int r;
    
        TestStart("test_normal");
        should_exit = 0;
        if (!(jmp_rval=setjmp(jump_env)))
        {
            r = my_div(12,3);
        }
    
        assert(jmp_rval==0);
        assert(r==4);
        TestEnd();
    }
    
    // test case
    void test_div0()
    {
        int jmp_rval;
        int r;
    
        TestStart("test_div0");
        should_exit = 1;
        expected_code = 2;
        if (!(jmp_rval=setjmp(jump_env)))
        {
            r = my_div(2,0);
        }
    
        assert(jmp_rval==1);
        TestEnd();
    }
    
    int main()
    {
        num_tests = 0;
        tests_passed = 0;
        done = 0;
        test_normal();
        test_div0();
        printf("Total tests passed: %d\n", tests_passed);
        done = 1;
        return !(tests_passed == num_tests);
    }
    

    In this example, you use setjmp before entering the function to test, then in the stubbed exit you call longjmp to return directly back to your test case.

    Also note that the redefined exit has a special variable that it checks to see if you actually want to exit the program and calls _exit to do so. If you don't do this, your test program may not quit cleanly.

提交回复
热议问题