Seems like it's a small bug in top.
See source code top.c:
 645         /*
 646          * Catches:
 647          *    SIGTSTP, SIGTTIN and SIGTTOU */
 648 static void sig_paused (int dont_care_sig) {
 661    fflush(stdout);
 662    raise(SIGSTOP);
 663    // later, after SIGCONT...
 664    if (-1 == tcsetattr(STDIN_FILENO, TCSAFLUSH, &Tty_raw))
 665       error_exit(fmtmk(N_fmt(FAIL_tty_set_fmt), strerror(errno)));
 666 #ifndef RMAN_IGNORED
 667    putp(Cap_rmam);
 668 #endif
 669    if (keypad_xmit) putp(keypad_xmit);
 670    putp(Cursor_state);
 671    Frames_signal = BREAK_sig;
 672    (void)dont_care_sig;
 673 } // end: sig_paused
 ...
3798    // lastly, establish a robust signals environment
3799    memset(&sa, 0, sizeof(sa));
3800    sigemptyset(&sa.sa_mask);
3801    //with user position preserved through SIGWINCH,we must avoid SA_RESTART
3802    sa.sa_flags = 0;
3803    for (i = SIGRTMAX; i; i--) {
3804       switch (i) {
....
3810          case SIGTSTP: case SIGTTIN: case SIGTTOU:
3811             sa.sa_handler = sig_paused;
3812             break;
....
3823       }
3824       sigaction(i, &sa, NULL);
3825    }
This is what happens:
- In line 3810, 
top explicitly registers its SIGTSTP handler sig_paused(). 
- When CTRL-Z is pressed, it sends SIGTSTP to 
top -b. 
- When 
top receives SIGTSTP, in sig_paused() it stops itself by sending SIGSTOP (line 662). 
fg sends SIGCONT to top and wakes it up. 
- In line 664 when 
top is waken up, it puts the tty in raw mode (it should not do this when -b is specified). 
- When the tty is in raw mode, keys like CTRL-C will not generate SIGINT so CTRL-C cannot kill it.