Is there a better way to do C style error handling?

前端 未结 10 2443
时光说笑
时光说笑 2021-02-20 06:43

I\'m trying to learn C by writing a simple parser / compiler. So far its been a very enlightening experience, however coming from a strong background in C# I\'m having some pro

10条回答
  •  星月不相逢
    2021-02-20 07:19

    It's a bigger problem when you have to repeat the same finalizing code before each return from an error. In such cases it is widely accepted to use goto:

    int func ()
    {
      if (a() < 0) {
        goto failure_a;
      }
    
      if (b() < 0) {
        goto failure_b;
      }
    
      if (c() < 0) {
        goto failure_c;
      }
    
      return SUCCESS;
    
      failure_c:
      undo_b();
    
      failure_b:
      undo_a();
    
      failure_a:
      return FAILURE;
    }
    

    You can even create your own macros around this to save you some typing, something like this (I haven't tested this though):

    #define CALL(funcname, ...) \
      if (funcname(__VA_ARGS__) < 0) { \ 
        goto failure_ ## funcname; \
      }
    

    Overall, it is a much cleaner and less redundant approach than the trivial handling:

    int func ()
    {
      if (a() < 0) {
        return FAILURE;
      }
    
      if (b() < 0) {
        undo_a();
        return FAILURE;
      }
    
      if (c() < 0) {
        undo_b();
        undo_a();
        return FAILURE;
      }
    
      return SUCCESS;
    }
    

    As an additional hint, I often use chaining to reduce the number of if's in my code:

    if (a() < 0 || b() < 0 || c() < 0) {
      return FAILURE;
    }
    

    Since || is a short-circuit operator, the above would substitute three separate if's. Consider using chaining in a return statement as well:

    return (a() < 0 || b() < 0 || c() < 0) ? FAILURE : SUCCESS;
    

提交回复
热议问题