The answer can be found in the termios(3)
man page:
VEOF (004, EOT, Ctrl-D) End-of-file character (EOF). More precisely:
this character causes the pending tty buffer to be sent to the
waiting user program without waiting for end-of-line. If it is
the first character of the line, the read(2) in the user program
returns 0, which signifies end-of-file. Recognized when ICANON
is set, and then not passed as input.
The first ^D
you press causes the line you have typed to be delivered to the cat
, so it gets a read(2)
result of a
(one character, no EOL char). The second ^D
causes read(2)
to return 0, which signifies EOF to cat
.