O caractere de escape “backspace” '\ b': comportamento inesperado?

101

Finalmente estou lendo K&R e aprendi algo nas primeiras páginas, que existe um caractere de escape de retrocesso \b,.

Então, vou testá-lo e há um comportamento muito estranho:

#include <stdio.h>

main ()
{
    printf("hello worl\b\bd\n");
}

A saída é

hello wodl

Alguém pode explicar isso?

Trilha de Oregon
fonte

Respostas:

145

Seu resultado irá variar dependendo do tipo de terminal ou programa de console em que você estiver, mas sim, na maioria \bé um backspace não destrutivo . Ele move o cursor para trás, mas não apaga o que está lá.

Então, para a hello worlparte, as saídas de código

olá mundo
          ^

... (onde ^mostra onde o cursor está) Em seguida, ele produz dois \bcaracteres que movem o cursor dois lugares para trás sem apagar (em seu terminal):

olá mundo
        ^

Observe que o cursor está agora no r. Em seguida, ele produz d, que substitui o re nos dá:

olá wodl
         ^

Finalmente, ele produz \n, que é uma nova linha não destrutiva (novamente, na maioria dos terminais, incluindo aparentemente o seu), de forma que o lpermanece inalterado e o cursor é movido para o início da próxima linha.

TJ Crowder
fonte
1
Se não apagar, por que o "r" desapareceu?
cesóide
1
@cesoid: "Seu resultado irá variar dependendo do tipo de terminal ou programa de console em que você estiver"
TJ Crowder
Acontece que seu exemplo não se ajusta à saída, portanto, não é um exemplo de uma explicação possível.
cesóide
5
@cesoid O ré substituído por d. A explicação ainda se encaixa.
syockit de
1
@cesoid: Interessante sobre o terminal. No Windows, os terminais cmd.exee command.comnem sempre são inseridos (você pode usar a tecla Ins para alternar o comportamento). Fiquei surpreso ao descobrir que o Terminal Gnome no meu computador * nix principal sempre insere, nem parece ter uma preferência por isso, muito menos alternar com base na chave Ins. Nunca percebi isso antes. É claro que quase nunca quero datilografia. :-)
TJ Crowder
122
..........
^ <= ponteiro para "cabeça de impressão"
            /* part1 */
            printf("hello worl");
olá mundo
          ^ <= ponteiro para "cabeça de impressão"
            /* part2 */
            printf("\b");
olá mundo
         ^ <= ponteiro para "cabeça de impressão"
            /* part3 */
            printf("\b");
olá mundo
        ^ <= ponteiro para "cabeça de impressão"
            /* part4 */
            printf("d\n");
olá wodl

^ <= ponteiro para "cabeça de impressão" na próxima linha
pmg
fonte
Se o cursor após a parte 4 estiver na letra 'l', ele não deveria ser substituído pelo '\ n'? (resultando em "hello wor")
lucas_turci
@lucas_turci: o problema é que o '\n'não tem representação na tela. O que já está lá permanece o mesmo; não substituído por um espaço ou qualquer outra representação de caractere.
pmg
44

Se você quiser um retrocesso destrutivo, você precisará de algo como

"\b \b"

ou seja, um backspace, um espaço e outro backspace.

Peter K.
fonte
Isso ainda deixa o personagem de espaço não é?
Pacerier
Bem, sim, mas o subsequente \bsignificará que o próximo caractere de saída o substituirá.
Peter K.
1
E se não houver nenhum personagem subsequente?
Pacerier de
Então não importa, não é?
Peter K.
1
Hmm. A menos que seu dispositivo implemente uma opção "excluir último caractere" (por exemplo, DEL / 0x7f), estou perplexo.
Peter K.
8

Não é muito difícil de explicar ... Isso é como digitar hello worl, pressionar a tecla de seta para a esquerda duas vezes, digitar de pressionar a tecla de seta para baixo.

Pelo menos, é assim que deduzo que seu terminal está interpretando os códigos \be \n.

Redirecione a saída para um arquivo e aposto que você obterá algo totalmente diferente. Embora você possa ter que olhar os bytes do arquivo para ver a diferença.

[editar]

Para elaborar um pouco, isso printfemite uma sequência de bytes:, hello worl^H^Hd^Jonde ^Hé o caractere ASCII # 8 e ^Jé o caractere ASCII # 10. O que você vê em sua tela depende de como seu terminal interpreta esses códigos de controle.

Nemo
fonte
1

Use um único backspace após cada caractere printf("hello wor\bl\bd\n");

Dorothea
fonte
"olá wod \ n"? O que isso significa?
Elias Hasle