The advantage of gotos is clear next to the alternatives. First, the dreadful pyramid style:<p><pre><code>  err = funcA(&amp;resourceA)
  if (succeeded(err)) {

      err = funcB(&amp;resourceB)
      if (succeeded(err)) {

          err = funcC(&amp;resourceC)
          if (succeeded(err)) {

              ...and so forth...

              cleanup(resourceC)
          }
          
          free(resourceB)
          
      }
      specialFree(resourceA);
  }

  return err;
  </code></pre>
A new indentation level for every single function that can fail or return a resource. Hard to read and hard to edit.<p>Even worse is duplicating the cleanup code:<p><pre><code>  err = funA(&amp;resourceA)
  if (failed(err)) {
      specialFree(resourceA);
      return err;
  }

  err = funB(&amp;resourceB)
  if (failed(err)) {
     free(resourceB);
     specialFree(resourceA);
     return err;
  }

  err = funC(&amp;resourceC)
  if (failed(err)) {
      cleanup(resourceC);
      free(resourceB);
      specialFree(resourceA);
      return err;
  }

  ...and so forth...
</code></pre>
Now with gotos:<p><pre><code>     err = funA(&amp;resourceA);
     if (failed(err))
         goto Error;
  
     err = funB(&amp;resourceB);
     if (failed(err))
         goto Error;
  
     err = funC(&amp;resourceC);
     if (failed(err))
         goto Error;
  
   Error:
     if (resourceA)
         specialFree(resourceA);
  
     if (resourceB)
         free(resourceB);
  
     if (resourceC)
         cleanup(resourceB);
  
     free err;
</code></pre>
Much better. If you use the same error code type across the project, define a macro for &quot;if (failed(err)) goto Error;&quot; to save the keystrokes and lines-of-code. Some projects prefer to use a different goto label for each exit point, somewhat in lieu of ifs.  The advantage of using ifs is that you can usually be loose about the order of resource cleanup.<p>This use of goto is widespread and highly structured, so tools should be able to handle it too.