this is solved ore cleanly with escape continuation/exceptions.
Perl also provides 'last LABEL', which is handy (lets you break out of any level of nesting).
I guess in a language like C where you can have neither and function calls are slow so the 'return' escape continuation is also unusable there is a reason to use goto for this.
You implement your loop macro such that it binds some variable to a continuation, that when invoked, exits the loop. Then when you want to exit the loop, you invoke the continuation.
(Loop exits, exceptions, returns from functions, etc. are all special cases of continuations.)
This is an improvement over something like Perl's "last LABEL" statement, because you can pass the continuation around and exit the loop from anywhere you desire.
In C/C++ I have longed for a parametrized break statement with value indicating number of nested loops to break at once. I'm sure this goes against some kind of lambda calculus CS ethos though.