String terminada em nulo - Null-terminated string

Na programação de computadores , uma string terminada em nulo é uma string de caracteres armazenada como uma matriz contendo os caracteres e terminada com um caractere nulo (um caractere com valor zero, denominado NUL neste artigo). Nomes alternativos são string C , que se refere à linguagem de programação C e ASCIIZ (embora C possa usar codificações diferentes de ASCII).

O comprimento de uma string é encontrado ao pesquisar o (primeiro) NUL. Isso pode ser lento, pois leva O ( n ) ( tempo linear ) em relação ao comprimento da corda. Isso também significa que uma string não pode conter um NUL (há um NUL na memória, mas está após o último caractere, não "dentro" da string).

História

Strings com terminação nula foram produzidas pela .ASCIZdiretiva das linguagens de montagem PDP-11 e pela diretiva da macro linguagem de montagem MACRO-10 para o PDP-10 . Elas são anteriores ao desenvolvimento da linguagem de programação C, mas outras formas de strings eram usadas com frequência. ASCIZ

Na época em que C (e as linguagens das quais ele foi derivado) foi desenvolvido, a memória era extremamente limitada, então usar apenas um byte de overhead para armazenar o comprimento de uma string era atraente. A única alternativa popular na época, geralmente chamada de "string Pascal" (um termo mais moderno é " prefixo de comprimento "), usava um byte inicial para armazenar o comprimento da string. Isso permite que a string contenha NUL e faça encontrar o comprimento de uma string já armazenada, precisa apenas de um acesso à memória (O (1) (constante) tempo ), mas limita o comprimento da string a 255 caracteres (em uma máquina usando bytes de 8 bits ) O designer de C Dennis Ritchie escolheu seguir a convenção de terminação nula para evitar a limitação do comprimento de uma string e porque manter a contagem parecia, em sua experiência, menos conveniente do que usar um terminador.

Isso teve alguma influência no design do conjunto de instruções da CPU . Algumas CPUs nas décadas de 1970 e 1980, como o Zilog Z80 e o DEC VAX , tinham instruções dedicadas para lidar com strings com prefixo de comprimento. No entanto, conforme a string terminada em nulo ganhou força, os designers da CPU começaram a levá-la em consideração, como visto, por exemplo, na decisão da IBM de adicionar as instruções "Logical String Assist" ao ES / 9000 520 em 1992 e as instruções da string vetorial para o IBM z13 em 2015.

O desenvolvedor do FreeBSD Poul-Henning Kamp , escrevendo no ACM Queue , referiu-se à vitória de strings terminadas em null sobre um comprimento de 2 bytes (não um byte) como "o erro de um byte mais caro" de todos os tempos.

Limitações

Embora seja simples de implementar, essa representação está sujeita a erros e problemas de desempenho.

A terminação nula historicamente criou problemas de segurança . Um NUL inserido no meio de uma string irá truncá-la inesperadamente. Um bug comum era não alocar o espaço adicional para o NUL, então ele era escrito na memória adjacente. Outra era não escrever o NUL, o que muitas vezes não era detectado durante o teste porque o bloco de memória já continha zeros. Devido ao custo de encontrar o comprimento, muitos programas não se importavam antes de copiar uma string para um buffer de tamanho fixo , causando um estouro de buffer se fosse muito longo.

A incapacidade de armazenar um zero requer que dados de texto e binários sejam mantidos distintos e controlados por funções diferentes (com as últimas exigindo que o comprimento dos dados também seja fornecido). Isso pode levar a redundância de código e erros quando a função errada é usada.

Os problemas de velocidade para encontrar o comprimento geralmente podem ser atenuados combinando-o com outra operação que seja O ( n ) de qualquer maneira, como em strlcpy. No entanto, isso nem sempre resulta em uma API intuitiva .

Codificações de caracteres

Strings com terminação nula exigem que a codificação não use um byte zero (0x00) em qualquer lugar, portanto, não é possível armazenar todas as strings ASCII ou UTF-8 possíveis . No entanto, é comum armazenar o subconjunto de ASCII ou UTF-8 - todos os caracteres, exceto NUL - em strings terminadas em nulo. Alguns sistemas usam " UTF-8 modificado " que codifica o NUL como dois bytes diferentes de zero (0xC0, 0x80) e, portanto, permite que todas as strings possíveis sejam armazenadas. Isso não é permitido pelo padrão UTF-8, porque é uma codificação muito longa e é vista como um risco à segurança. Em vez disso, algum outro byte pode ser usado como fim de string, como 0xFE ou 0xFF, que não são usados ​​em UTF-8.

UTF-16 usa números inteiros de 2 bytes e como qualquer byte pode ser zero (e de fato todos os outros bytes são, ao representar texto ASCII), não podem ser armazenados em uma string de bytes terminada em nulo. No entanto, algumas linguagens implementam uma sequência de caracteres UTF-16 de 16 bits , terminada por um NUL de 16 bits

Melhorias

Muitas tentativas de tornar o manuseio de strings C menos sujeito a erros foram feitas. Uma estratégia é adicionar funções mais seguras, como strdupe strlcpy, enquanto descontinua o uso de funções não seguras , como gets. Outra é adicionar um invólucro orientado a objetos em torno das strings C para que apenas chamadas seguras possam ser feitas. No entanto, é possível chamar as funções não seguras de qualquer maneira.

A maioria das bibliotecas modernas substituem strings C por uma estrutura contendo um valor de comprimento de 32 bits ou maior (muito mais do que jamais foi considerado para strings prefixadas por comprimento) e, muitas vezes, adicionam outro ponteiro, uma contagem de referência e até mesmo um NUL para acelerar a conversão de volta a uma string C. A memória é muito maior agora, de modo que se a adição de 3 (ou 16, ou mais) bytes a cada string for um problema real, o software terá que lidar com tantas strings pequenas que algum outro método de armazenamento economizará ainda mais memória (por exemplo, pode haver tantas duplicatas que uma tabela hash usará menos memória). Os exemplos incluem a C ++ Standard Template Library std::string , o Qt QString , o MFC CString e a implementação baseada em C CFStringda Core Foundation , bem como seu irmão Objective-CNSString da Foundation , ambos da Apple. Estruturas mais complexas também podem ser usadas para armazenar cordas, como a corda .

Veja também

Referências