Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this revised version, we have used a goto-chain in replacement of each individual return segment. If there is no error, control flow will fall through to the SUCCESS label, release all of the resources and return 0RET_SUCCESS. In the case of an error, the return value will be set to RET_ERROR, control flow will jump to the proper failure label, and the appropriate memory resources will be freed released before returning an error.

Code Block
bgColor#CCCCFF
// ... assume the same struct as above ...

#define RET_SUCCESS  0
#define RET_ERROR   -1

int do_something(void){
  FILE *fin;
  object_t *obj1, *obj2;
  int ret_val = RET_SUCCESS; // Initially assume a successful return value

  fin = fopen("some_file", "r");
  if (fin == NULL){
    ret_val = RET_ERROR;
    goto FAIL_FIN;
  }

  obj1 = malloc(sizeof(object_t));
  if (obj1 == NULL){
    ret_val = RET_ERROR;
    goto FAIL_OBJ1;
  }

  obj2 = malloc(sizeof(object_t));
  if (obj2 == NULL){
    ret_val = RET_ERROR;
    goto FAIL_OBJ2;
  }


  // ... more code ...


SUCCESS:     // Free everything and return normally
  fclose(fin);
  free(obj1);
  free(obj2);
  return 0;

FAIL_OBJ2:   // Otherwise, free only the objects inwe orderallocated
  free(obj1);

FAIL_OBJ1:
  fclose(fin);

FAIL_FIN:
  return -1ret_val;
}

The benefits of this method are that the code is cleaner and we prevent the rewriting of similar code upon every function error.

...