Executando verificação de segurança...
15

CR e LF nos marcadores de "fim de linha"

Cada um dos três sistemas operacionais, mais comuns em notebooks e desktops, utilizam diferentes marcadores de "fim de linha".

No Windows a marcação de "fim de linha" acontece com 2 caracteres: CR+LF
No UNIX/Linux, com um caractere: LF
No MAC, com um caractere: originalmente, CR, e a partir da versão X (10), LF

Vamos, neste artigo, ignorar essa discordância e focar em entender o que são CR e LF?

Primeiramente, indo direto ao ponto, os significados desses caracteres são:

  • CR: Carriage Return, que significa "voltar para o início da linha"; é o caractere 13, 0x0D, também representado por \r (return).
  • LF: Line Feed, que significa "ir para a próxima linha"; é o caractere 10, 0x0A, também representado por \n (new line).

"Caracteres" que são "sinais"

Computadores trabalham, em sua grande maioria hoje, com sistema binário.
Sistema binário nada mais é que um sistema numérico em que os números utilizam apenas dois algarismos em suas representações, 0 e 1.

Para termos letras, símbolos e outras coisas nos computadores, além de valores para cálculos, temos que dar significados especiais a alguns valores binários.

Uma das primeiras tentativas de padronização desses valores que foi amplamente aceita foi a tabela ASCII, formalizada no início dos anos 1960. Esta tabela se referia a cada valor como um "sinal", no sentido de "sinal" elétrico processado nos computadores, equivalente a um valor binário de sete dígitos. Assim, a tabela ASCII definiu "significados" para os "sinais" de 0 a 127, que são os possíveis valores desse número.

Essa tabela lista:

  • 95 símbolos gráficos, imprimíveis: letras, algarismos, símbolos de pontuação e matemáticos; e
  • 33 sinais de controle, não-imprimíveis.

A tabela ASCII não criou símbolos, apenas propôs uma padronização. É claro que letras e algarismos já existiam antes da tabela ASCII. :)
Da mesma forma, vários sinais de controle também já existiam. Alguns, como os CR e LF, já estavam em uso há décadas, nos padrões de comunicação por telégrafos.

CR e LF são "sinais" não-imprimíveis, que representam comandos. Por isso, vou chamá-los de "comandos".

Contexto histórico

Espero que o conhecimento de um pouco de história facilite o entendimento do uso atual dos comandos CR e LF.

CR e LF foram definidos em uma época em que não existiam monitores. Então, essas "linhas" citadas nas descrições de suas funções ("voltar para o início da linha" e "ir para a próxima linha"), não são "linhas" de texto na tela, são "linhas" impressas.

As primeiras impressoras eram inspiradas em máquinas de escrever e, como nestas, uma linha recebia uma sequência de caracteres que eram "carimbados" no papel, em sequência, da esquerda para a direita. Um exemplo dessa impressora é o Teletipo Modelo 33.

Ao chegar na margem direita, ou no último caractere que deveria ser impresso em uma determinada linha, era necessário mandar um comando para a impressora reposicionar o cabeçote de impressão no início da próxima linha.

Reposicionar o cabeçote de impressão seria uma ação semelhante a reposicionarmos o cursor que indica onde estamos escrevendo em um editor de texto. Onde estiver o cursor é onde irá ser inserido o próximo caractere digitado.

Imprimindo na Teletipo Modelo 33

Nesse tipo de impressora, o "comando" reposicionar o cabeçote de impressão no início da próxima linha era duplo. Um CR e um LF.
Agora, se você reler o significado desses caracteres talvez faça mais sentido.

Um CR, "voltar para o início da linha", posiciona o cabeçote junto à margem esquerda, e um LF, "ir para a próxima linha", avançava o papel o suficiente para que novas impressões sejam feitas abaixo das anteriores.

Vamos definir uma tarefa de impressão, que será utilizada em exemplos a seguir: Imprimir "Oi" no início da linha e "--" abaixo (sem as aspas).

Imaginando o fluxo de dados enviado para a impressora para executar a tarefa definida, depois de iniciarmos a comunicação com a impressora, esta reage a cada caractere enviado.

Enviamos "O", imprime "O", enviamos "i", imprime "i", enviamos CR, volta o cabeçote para o início da mesma linha, enviamos LF, a impressora avançava o papel uma linha, enviamos "-", imprime "-", enviamos "-", imprime "-".

Isso foi o suficiente para concluirmos a tarefa.

Me parece que isso esclarece bem o significado de CR e LF.

Imprimindo na IBM 1132

Agora vou falar de "impressora de linha". Também muito antiga, porém mais moderna que a citada anteriormente. Um exemplo: IBM 1132

Essas impressoras não tinham, como na Teletipo Modelo 33, um cabeçote que se reposicionava para imprimir um caractere em diferentes posições na linha.
Essas impressoras tinham 132 "cabeçotes" fixos, um "cabeçote" para cada possível posição de impressão na linha, e imprimiam em um formulário largo.

Só por curiosidade, exatamente esse modelo de impressora de linha eu cheguei a utilizar na UFF.

Agora, imaginando o fluxo de dados enviado para a impressora para executar a tarefa definida e a reação desta a cada caractere enviado.

Enviamos "O", prepara o primeiro cabeçote para imprimir "O", enviamos "i", prepara o segundo cabeçote para imprimir "i", (não enviamos CR, afinal não existe para ela "mover cabeçote") enviamos LF, entende que tudo está preparado para a impressão da linha, então todos os cabeçotes imprimem ao mesmo tempo, ou seja, é impresso "Oi", então, avançava o papel uma linha e reposiciona todos os cabeçotes para "imprimir" espaço (equivalente a não imprimir nada), enviamos "-", prepara o primeiro cabeçote para imprimir "-", enviamos "-", prepara o segundo cabeçote para imprimir "-", enviamos LF, manda "--" para o papel, avançava o papel uma linha e reposiciona todos os cabeçotes.

Esse segundo exemplo foi mostrado para levantar dois pontos importantes.

Primeiramente, para ficar claro que não é obrigatório o uso dos mesmos comandos em todos os contextos. Dependendo do contexto o uso dos comandos pode mudar. Na primeira impressora o CR era necessário. Na segunda não.

Além disso, há contextos em que um caractere de comando é útil para indicar um estado, não apenas para indicar uma ação. No caso, estou falando do uso do LF, que, mais que comandar "avance o papel", indica que a linha está concluída.

Voltando aos tempos atuais, lembro dois pontos semelhantes aos apresentados acima, porém em outros contextos.

Primeiramente, o uso de CR e/ou LF para indicar fim de cada linha em um arquivo de texto, que muda conforme o contexto. No caso, conforme o sistema operacional.

Além disso, arquivos de configuração muitas vezes exigem que linhas com informações relevantes apresentem um indicador de fim de linha, mesmo que não haja nenhuma informação a ser apresentada na próxima linha.

Conclusão

Enfim, espero que o assunto "fim de linha" tenha ficado bem mais claro para vocês agora.

Carregando publicação patrocinada...
2

Bom levantamento histórico, AnselmoBD!! Aprender o real motivo das implementações nos facilita memorizar um determinado conceito ou consenso. O nível de seu texto buscou detalhes históricos fazendo-me lembrar das fitas de papel perfurado e o barulho das máquinas teletipo!

img

Outra novidade que aprendi com seu post foi saber que o Mac, a partir de uma dada versão, passou a empregar outro tipo de terminador de linha, a mesma empregada pelos sistemas Linux.

2

Legal que gostou! Obrigado!

Sim, máquinas Teletipo Modelo 33, além de imprimirem "texto" em papel (impressora) liam e "escreviam", perfuravam, fitas de papel como a que você representou acima.
Nunca tive experiência com fitas perfuradas.

Convivi com a impressora de linha IBM 1132, na faculdade, UFF, como citado no meu texto.
Essa, sim, uma fonte absurda de barulho!
Quando estava imprimindo era impossível ouvir qualquer outra coisa, afinal seus mais de cem cabeçotes funcionando ao mesmo tempo poderiam ser comparados a mais de cem pessoas datilografando nas antigas máquinas de escrever, muito rápido ao mesmo tempo. Consegue imaginar? :-)

Também na UFF programei em WATFIV (falávamos "uatifaivi"), Waterloo Fortran IV, em cartões perfurados.
Tenho quase certeza que utilizada uma IBM 129, como a que pode ser vista nesta página
Passei muito tempo na frente desse tipo de máquina. :-)

2

Excelente texto e explicação, não sabia que vinha lá das máquinas de escrever.

Uma dúvida quanto ao Git, uso WSL no Windows e majoritariamente programo pelo WSL (LF), porém algumas IDEs montam para Windows e convertem para CRLF, existe um real problema em ter os arquivos com diferentes fins de linha no repositório ou isso é escovação de bits?

3

Oi, Marlon e demais!

O Andrei, da equipe do Curso.dev, respondeu a minha pergunta sobre o tema.

Segue abaixo a resposta dele:

... O Git oferece a opção de converter automaticamente o caractere de fim de linha dependendo do sistema operacional. Isso pode ser feito através da opção core.autocrlf. Veja o que diz a documentação:

"Se você estiver programando no Windows e trabalhando com pessoas que não estão (ou vice-versa), provavelmente terá problemas de fim de linha em algum momento. Isso ocorre porque o Windows usa um caractere de retorno e um caractere de avanço de linha para novas linhas em seus arquivos, enquanto os sistemas macOS e Linux usam apenas o caractere de avanço de linha. Este é um fato sutil, mas incrivelmente irritante, do trabalho multiplataforma; muitos editores no Windows substituem silenciosamente os finais de linha existentes no estilo LF por CRLF ou inserem ambos os caracteres de fim de linha quando o usuário pressiona a tecla Enter.

O Git pode lidar com isso convertendo automaticamente os finais de linha CRLF em LF quando você adiciona um arquivo ao índice e vice-versa quando ele verifica o código no seu sistema de arquivos. Você pode ativar essa funcionalidade com a configuração core.autocrlf."

E o Andrei também indicou o mesmo link que o citado pelo ghostnetrn.

1

A todos que responderam ao meu texto elogiando, agradeço muito!
Fico feliz pelo texto ter sido útil.
(Não agradeci a cada um indvidualmenet, pois entendi que iria contra as regras do TabNews)

Quando à sua dúvida, Marlon, mandei uma pergunta justamente sobre isso para o Filipe no Curso.dev.

Assim que ele reponder lá, ou que eu achar a resposta em outra fonte, compartilharei o conhecimento aqui.

1

Postagem excelente, principalmente por ir lá nos tempos das máquinas de escrever e das primeiras impressoras.

Isso me fez lembrar de um contexto específico onde o LF não faz sentido, mas o CR sim:

Em sistemas embarcados, é muito comum utilizarmos aqueles displays de 1 linha por X caracteres, para exibir informações básicas em texto (o rádio do meu automóvel mesmo possui um display desse tipo). Nessa situação, não existe o comando de avançar linha, mas o retorno do ponteiro de caracteres é essencial para limpar e escrever novos caracteres.

Outro caso em que o CR sozinho é muito utilizado é no terminal de comandos (Linux/Mac) ou cmd/PowerShell (Windows), para substituir textos já impressos na tela.

1

Muito obrigado!

Legal você citar esses contextos de uso do CR sem o LF!

Só vale lembrar que "apagar a linha" não faz parte da função original do CR, que é apenas reposicionar o cabeçote (ou cursor) no início da linha. Em um editor de textos, seria algo como a funcionalidade da tecla "Home".

Nada impede que algum equipamento ou software implemente algo assim, que além de reposicionar, apaga a linha, mas seria uma adaptação. Não havendo nenhum problema nisso.

Aproveito para falar de mais um caractere de comando: o BS

Os exemplos de contexto que você trouxe me fizeram lembrar de um recurso que já utilizei.

Ao fazer uma rotina demorada executada no console, as vezes eu queria:

  1. acompanhar a execução, para saber se não travou; ou
  2. saber quanto tempo faltava para a rotina chegar ao fim.

No primeiro caso já utilizei a ideia de imprimir os caracteres "-|/", um de cada vez, em sequência e na mesma posição da tela, de modo a "parecer" (com boa vontade) uma "hélice" girando. Enquanto estiver girando, sei que o programa não "travou".

Para fazer isso eu não utilizava o comando CR, mas sim o BS.

  • BS: Back-space, que significa "retornar um carectere"; é o caractere 8, 0x08, também representado por \b.

Obs.: Assim como o comando CR, o BS, a princípio, apenas reposiciona, não apaga nada. Quando, nos editores de texto, decidiram que o comando back-space deveria apagar o caractere anterior, além de voltar uma posição, foi uma adaptação da ideia original. Muito boa por sinal!

Se você tiver o Python 3 em sua máquina pode verificar a primeira ideia citada acima, utilizando o modo interativo.

Digite python3 e cole o seguinte código:

import time

def helice(contador):
  print("Executando ", end="", flush=True)
  posicoes = "-\|/"
  bs = '\b'
  for i in range(contador):
    print(posicoes[i%4], end="", flush=True)
    time.sleep(0.1)  # aguarda 0,1 segundos, simulando demora de processamento
    print(bs, end="", flush=True)
  print(" ")

helice(30)  # para ver a hélice rodando por 3 segundos

Quanto à segunda ideia citada acima, o avô das barras de progresso, a ideia é que, se sabemos quantas vezes uma tarefa será executada, então poderiamos imprimir um contador regressivo.

Segue código exemplo:

import time

def regressivo(contador):
  print("Aguarde ", end="", flush=True)
  tamanho = len(str(contador))
  bs = '\b'*tamanho
  for i in range(contador, 0, -1):
    print(f"{i:{tamanho}}", end="", flush=True)
    time.sleep(0.1)  # aguarda 0,1 segundos, simulando demora de processamento
    print(bs, end="", flush=True)
  print(f"{0:{tamanho}}")

regressivo(30)  # para ver o contador regressivo iniciando em 30

Perceba que, propositalmente, a informação de execução não aparece no início da linha, o que poderia remeter à ideia do CR.

Obs.: Os códigos python acima foram feitos apenas para esta demonstração de uso do BS.

1
1