Yes, this is well defined. From stmt.goto#1
The goto statement unconditionally transfers control to the statement labeled by the identifier.
The identifier shall be a label located in the current function.
There are some restrictions, e.g. a case label cannot cross a non-trivial initialization
goto error;
int i = 42;
error: // error: crosses initialization of i
But these don't apply to your example. Also, in the case of crossing an initialization, this is a hard compiler error, so you don't have to worry about undefined behavior.
Note that once you jump to the case label error
, you're effectively inside the true branch of the if
condition, and it doesn't matter that you got there via a goto
. So you're guaranteed that the else
branch will not be executed.