You can express every conceivable algorithm in both assembly and C (because Turing-completeness and all that), but that does not mean you can do it equally efficiently for a given CPU.I know very little about assembly but I always assumed C could do anything assembly could even if less efficiently.
For example, many assembly function return two results - an actual result and a flag (like carry or zero) telling you whether the function call succeeded in the first place. In C, functions only return one result; returning two requires returning a complex data structure, which compiles to far more instructions and uses more memory.
Another area are rotation instructions. C does not have operators for rotations, so you have to express those as "(A << N) | (A >> M-N)" or similar and hope that the compiler recognizes those. But in C, overflow on signed integers is undefined (implementation-defined) behavior and flags are not exposed at all, so a lot of assembly-level trickery "rotate the top bit into the sign bit" for math just does not translate well.
And finally, C compilers do not generate all instructions a CPU can run. Especially older CPUs have many special instructions which require a complex environmental setup to be used efficiently - compilers are not smart enough to recognize it. For common cases (like memset or memcpy), the C library may contain hand-written assembly for optimization, but general code will not use it. Which is why C compilers support inline assembly or similar means.
Well-optimized, tricky assembly code is very hard to translate into reasonably efficient C.
GOTO in C cannot go anywhere, it needs to stay within the same stack frame. Computed GOTO (i.e. "goto *ptr") is a compiler-extension and also only legal within the same stack frame. If you want to go further, you have to use setjmp/longjmp which come with a ton of caveats.How do you mean "because GOTO can be anywhere"? Goto in C can be anywhere too.