> I don't think that's right. C is compiled into an intermediate representation first. It's true that you can ask GCC etc. to generate assembly output, but it's not the default.
Just because there's an IR within the compiler doesn't mean there's no "assemble" stage. What do you think the "-pipe" flag to gcc is for? It pipes the compiler output into the assembler, rather than using a temporary .s file.
gcc has four main stages going from source to executable: preprocessor->compiler->assembler->linker.
Edit, for your convenience, gcc -save-temps example:
> [user@host /tmp/foo]$ ls
> f.c
> [user@host /tmp/foo]$ cat f.c
> #include
>
> int main(int argc, char **argv)
> {
> puts("Hello world!");
>
> return 0;
> }
> [user@host /tmp/foo]$ gcc -o f -save-temps f.c
> [user@host /tmp/foo]$ ls -l
> total 48
> -rwxr-xr-x 1 user user 15416 Jan 13 16:50 f
> -rw-r--r-- 1 user user 91 Jan 13 16:49 f.c
> -rw-r--r-- 1 user user 17145 Jan 13 16:50 f.i
> -rw-r--r-- 1 user user 1496 Jan 13 16:50 f.o
> -rw-r--r-- 1 user user 515 Jan 13 16:50 f.s
> [user@host /tmp/foo]$ cat f.s
> .file "f.c"
> .text
> .section .rodata
> .LC0:
> .string "Hello world!"
> .text
> .globl main
> .type main, @function
> main:
> .LFB0:
> .cfi_startproc
> pushq %rbp
> .cfi_def_cfa_offset 16
> .cfi_offset 6, -16
> movq %rsp, %rbp
> .cfi_def_cfa_register 6
> subq $16, %rsp
> movl %edi, -4(%rbp)
> movq %rsi, -16(%rbp)
> leaq .LC0(%rip), %rax
> movq %rax, %rdi
> call puts@PLT
> movl $0, %eax
> leave
> .cfi_def_cfa 7, 8
> ret
> .cfi_endproc
> .LFE0:
> .size main, .-main
> .ident "GCC: (GNU) 13.1.1 20230429"
> .section .note.GNU-stack,"",@progbits
> [user@host /tmp/foo]$ ./f
> Hello world!
> [user@host /tmp/foo]$
>