Manuseio de string C - C string handling

A linguagem de programação C tem um conjunto de funções que implementam operações em strings (strings de caracteres e strings de bytes) em sua biblioteca padrão . Várias operações, como cópia, concatenação , tokenização e pesquisa são suportadas. Para cadeias de caracteres, a biblioteca padrão usa a convenção de que as cadeias têm terminação nula : uma cadeia de n caracteres é representada como uma matriz de n + 1 elementos, o último dos quais é um NULcaractere (com valor numérico 0).

O único suporte para strings na linguagem de programação apropriada é que o compilador traduz constantes de string entre aspas em strings terminadas em nulo.

Definições

Uma string é definida como uma sequência contígua de unidades de código terminadas pela primeira unidade de código zero (freqüentemente chamada de unidade de código NUL ). Isso significa que uma string não pode conter a unidade de código zero, pois a primeira vista marca o final da string. O comprimento de uma string é o número de unidades de código antes da unidade de código zero. A memória ocupada por uma string é sempre uma unidade de código a mais do que o comprimento, pois é necessário espaço para armazenar o terminador zero.

Geralmente, o termo string significa uma string em que a unidade de código é do tipo char, que tem exatamente 8 bits em todas as máquinas modernas. C90 define cadeias largas que usam uma unidade de código do tipo wchar_t, que é de 16 ou 32 bits em máquinas modernas. Isso foi planejado para Unicode, mas é cada vez mais comum usar UTF-8 em strings normais para Unicode.

Strings são passados ​​para funções passando um ponteiro para a primeira unidade de código. Visto que char*e wchar_t*são tipos diferentes, as funções que processam cadeias de caracteres largas são diferentes daquelas que processam cadeias de caracteres normais e têm nomes diferentes.

Literais de string ( "text"no código-fonte C) são convertidos em matrizes durante a compilação. O resultado é uma matriz de unidades de código contendo todos os caracteres mais uma unidade de código zero à direita. Em C90 L"text"produz uma corda larga. Um literal de string pode conter a unidade de código zero (uma maneira é colocá- \0lo na fonte), mas isso fará com que a string termine nesse ponto. O resto do literal será colocado na memória (com outra unidade de código zero adicionada ao final), mas é impossível saber se essas unidades de código foram traduzidas do literal de string, portanto, esse código-fonte não é um literal de string.

Codificações de caracteres

Cada string termina na primeira ocorrência da unidade de código zero do tipo apropriado ( charou wchar_t). Consequentemente, uma string de bytes ( char*) pode conter caracteres não NUL em ASCII ou qualquer extensão ASCII , mas não caracteres em codificações como UTF-16 (mesmo que uma unidade de código de 16 bits possa ser diferente de zero, seu byte alto ou baixo pode ser zero). As codificações que podem ser armazenadas em strings largas são definidas pela largura de wchar_t. Na maioria das implementações, wchar_ttem pelo menos 16 bits e, portanto, todas as codificações de 16 bits, como UCS-2 , podem ser armazenadas. Se wchar_tfor de 32 bits, as codificações de 32 bits, como UTF-32 , podem ser armazenadas. (O padrão requer um "tipo que contém qualquer caractere largo", que no Windows não é mais verdadeiro, pois o UCS-2 para o UTF-16 muda.) C ++ 11 e C11 adicionam dois tipos com larguras explícitas char16_te char32_t.

Codificações de largura variável podem ser usadas em strings de byte e strings largas. O comprimento da string e os deslocamentos são medidos em bytes ou wchar_t, não em "caracteres", o que pode ser confuso para programadores iniciantes. UTF-8 e Shift JIS são freqüentemente usados ​​em strings de bytes C, enquanto UTF-16 é freqüentemente usado em strings C largas quando wchar_ttem 16 bits. Truncar strings com caracteres de comprimento variável usando funções como strncpypode produzir sequências inválidas no final da string. Isso pode ser inseguro se as partes truncadas forem interpretadas por um código que presuma que a entrada é válida.

O suporte para literais Unicode, como char foo[512] = "φωωβαρ";(UTF-8) ou wchar_t foo[512] = L"φωωβαρ";(UTF-16 ou UTF-32, depende de wchar_t) é definido pela implementação e pode exigir que o código-fonte esteja na mesma codificação, especialmente para charonde os compiladores podem apenas copiar o que estiver entre as aspas. Alguns compiladores ou editores exigirão a inserção de todos os caracteres não ASCII como \xNNsequências para cada byte de UTF-8 e / ou \uNNNNpara cada palavra de UTF-16. Desde C11 (e C ++ 11), uma nova char foo[512] = u8"φωωβαρ";sintaxe literal está disponível que garante UTF-8 para um literal de bytestring.

Visão geral das funções

A maioria das funções que operam em strings C são declaradas no string.hcabeçalho ( cstringem C ++), enquanto funções que operam em strings C são declaradas no wchar.hcabeçalho ( cwcharem C ++). Esses cabeçalhos também contêm declarações de funções usadas para manipular buffers de memória; o nome é, portanto, um nome impróprio.

As funções declaradas em string.hsão extremamente populares, pois, como parte da biblioteca padrão C , têm a garantia de funcionar em qualquer plataforma que suporte C. No entanto, existem alguns problemas de segurança com essas funções, como estouros de buffer em potencial quando não usadas com cuidado e adequadamente , fazendo com que os programadores prefiram variantes mais seguras e possivelmente menos portáveis, das quais algumas populares estão listadas abaixo. Algumas dessas funções também violam constância ao aceitar um constponteiro de string e retornar um não- constponteiro dentro da string. Para corrigir isso, alguns foram separados em duas funções sobrecarregadas na versão C ++ da biblioteca padrão.

Na documentação histórica, o termo "caractere" era frequentemente usado em vez de "byte" para strings C, o que leva muitos a acreditar que essas funções de alguma forma não funcionam para UTF-8 . Na verdade, todos os comprimentos são definidos em bytes e isso é verdade em todas as implementações, e essas funções funcionam tão bem com UTF-8 quanto com codificações de byte único. A documentação do BSD foi corrigida para deixar isso claro, mas a documentação do POSIX, Linux e Windows ainda usa "caractere" em muitos lugares onde "byte" ou "wchar_t" é o termo correto.

As funções para lidar com buffers de memória podem processar sequências de bytes que incluem bytes nulos como parte dos dados. Os nomes dessas funções geralmente começam com mem, em oposição ao strprefixo.

Constantes e tipos

Nome Notas
NULL Expansão da macro para a constante de ponteiro nula ; ou seja, uma constante que representa um valor de ponteiro que é garantido não ser um endereço válido de um objeto na memória.
wchar_t Tipo usado para uma unidade de código em cadeias largas, geralmente um valor de 16 bits ou 32 bits sem sinal. Nenhuma interpretação específica é especificada para essas unidades de código; o padrão C requer apenas que wchar_t seja largo o suficiente para conter o conjunto de caracteres mais amplo entre as localidades do sistema com suporte . Teoricamente, wchar_t pode ter o mesmo tamanho que char e, portanto, não é capaz de conter unidades de código UTF-32 ou UTF-16 .
wint_t Tipo inteiro que pode conter qualquer valor de wchar_t, bem como o valor da macro WEOF. Este tipo não é alterado por promoções integrais. Normalmente, um valor com sinal de 32 bits.
mbstate_t Contém todas as informações sobre o estado de conversão necessário de uma chamada para uma função para a outra.

Funções


String de byte

Corda larga
Descrição

Manipulação de cordas
strcpy wcscpy Copia uma string para outra
strncpy wcsncpy Grava exatamente n bytes, copiando da fonte ou adicionando nulos
strcat wcscat Acrescenta uma string a outra
strncat wcsncat Acrescenta não mais do que n bytes de uma string para outra
strxfrm wcsxfrm Transforma uma string de acordo com a localidade atual

Exame de cordas
strlen wcslen Retorna o comprimento da string
strcmp wcscmp Compara duas strings ( comparação de três vias )
strncmp wcsncmp Compara um número específico de bytes em duas strings
strcoll wcscoll Compara duas strings de acordo com a localidade atual
strchr wcschr Encontra a primeira ocorrência de um byte em uma string
strrchr wcsrchr Encontra a última ocorrência de um byte em uma string
strspn wcsspn Retorna o número de bytes iniciais em uma string que estão em uma segunda string
strcspn wcscspn Retorna o número de bytes iniciais em uma string que não estão em uma segunda string
strpbrk wcspbrk Encontra em uma string a primeira ocorrência de um byte em um conjunto
strstr wcsstr Encontra a primeira ocorrência de uma substring em uma string
strtok wcstok Divide uma string em fichas
Diversos strerror N / D Retorna uma string contendo uma mensagem derivada de um código de erro

Manipulação de memória
memset wmemset Preenche um buffer com um byte repetido
memcpy wmemcpy Copia um buffer para outro
memmove wmemmove Copia um buffer para outro, possivelmente sobrepondo, buffer
memcmp wmemcmp Compara dois buffers (comparação de três vias)
memchr wmemchr Encontra a primeira ocorrência de um byte em um buffer
  1. ^ Para funções de string ampla, substituawchar_tpor "byte" na descrição

Funções multibyte

Nome Descrição
mblen Retorna o número de bytes no próximo caractere multibyte
mbtowc Converte o próximo caractere multibyte em um caractere largo
wctomb Converte um caractere largo em sua representação multibyte
mbstowcs Converte uma string multibyte em uma string larga
wcstombs Converte uma string larga em uma string multibyte
btowc Converta um caractere de byte único em um caractere largo, se possível
wctob Converta um caractere largo em um caractere de byte único, se possível
mbsinit Verifica se um objeto de estado representa o estado inicial
mbrlen Retorna o número de bytes no próximo caractere multibyte, determinado estado
mbrtowc Converte o próximo caractere multibyte em um caractere largo, determinado estado
wcrtomb Converte um caractere largo em sua representação multibyte, determinado estado
mbsrtowcs Converte uma string multibyte em uma string larga, determinado estado
wcsrtombs Converte uma string larga em uma string multibyte, dado o estado

Todas essas funções levam um ponteiro para um mbstate_tobjeto que o chamador deve manter. Isso foi originalmente planejado para rastrear os estados de mudança noMBcodificações, mas as modernas, como UTF-8, não precisam disso. No entanto, essas funções foram projetadas no pressuposto de que obanheirocodificação não é uma codificação de largura variável e, portanto, foi projetada para lidar com exatamente umwchar_tpor vez, passando-o por valor em vez de usar um ponteiro de string. Como UTF-16 é uma codificação de largura variável, ombstate_t foi reutilizado para rastrear pares substitutos na codificação ampla, embora o chamador ainda deva detectar e chamar mbtowc duas vezes para um único personagem.

Conversões numéricas


String de byte

Corda larga
Descrição
atof N / D converte uma string em um valor de ponto flutuante ('atof' significa 'ASCII para flutuar')
atoi
atol
atoll
N / D converte uma string em um inteiro ( C99 ) ('atoi' significa 'ASCII para inteiro')
strtof( C99 )
strtod
strtold( C99 )
wcstof( C99 )
wcstod
wcstold( C99 )
converte uma string em um valor de ponto flutuante
strtol
strtoll
wcstol
wcstoll
converte uma string em um inteiro assinado
strtoul
strtoull
wcstoul
wcstoull
converte uma string em um inteiro sem sinal
  1. ^ Aqui string refere-se a string de byte ou string larga

A biblioteca padrão C contém várias funções para conversões numéricas. As funções que lidam com cadeias de bytes são definidas no stdlib.hcabeçalho ( cstdlibcabeçalho em C ++). As funções que lidam com strings largas são definidas no wchar.hcabeçalho ( cwcharcabeçalho em C ++).

As strtoxxxfunções não são const-corretas , pois aceitam um constponteiro de string e retornam um não- constponteiro dentro da string.

Além disso, desde a Emenda Normativa 1 (C95), as atoxxfunções são consideradas subsumidas por strtoxxxfunções, razão pela qual nem C95 nem qualquer padrão posterior fornece versões de caracteres amplos dessas funções. O argumento contra atoxxé que eles não diferenciam entre um erro e a 0.

Extensões populares

Nome Plataforma Descrição
bzero POSIX , BSD Preenche um buffer com zero bytes, obsoleto por memset
memccpy SVID , POSIX copia até um número especificado de bytes entre duas áreas de memória, que não devem se sobrepor, parando quando um determinado byte é encontrado.
mempcpy GNU uma variante de memcpyretornar um ponteiro para o byte após o último byte escrito
strcasecmp POSIX, BSD versões que não diferenciam maiúsculas de minúsculas de strcmp
strcat_s janelas uma variante strcatdisso verifica o tamanho do buffer de destino antes de copiar
strcpy_s janelas uma variante strcpydisso verifica o tamanho do buffer de destino antes de copiar
strdup POSIX aloca e duplica uma string
strerror_r POSIX 1, GNU uma variante strerrordisso é thread-safe. A versão GNU é incompatível com a versão POSIX.
stricmp janelas versões que não diferenciam maiúsculas de minúsculas de strcmp
strlcpy BSD, Solaris uma variante strcpydisso trunca o resultado para caber no buffer de destino
strlcat BSD, Solaris uma variante strcatdisso trunca o resultado para caber no buffer de destino
strsignal POSIX: 2008 retorna a representação de string de um código de sinal . Não é seguro para thread.
strtok_r POSIX uma variante strtokdisso é thread-safe

Replacements

Apesar da necessidade bem estabelecida de substituir strcate strcpycom funções que não permitem buffer overflows, nenhum padrão aceito surgiu. Em parte, isso se deve à crença equivocada de muitos programadores C de que strncate strncpytêm o comportamento desejado; no entanto, nenhuma das funções foi projetada para isso (destinavam-se a manipular buffers de string de tamanho fixo com preenchimento nulo, um formato de dados menos comumente usado em software moderno), e o comportamento e os argumentos não são intuitivos e muitas vezes escritos incorretamente, mesmo por especialistas programadores.

A substituição mais popular são as funções strlcate strlcpy, que apareceram no OpenBSD 2.4 em dezembro de 1998. Essas funções sempre gravam um NUL no buffer de destino, truncando o resultado se necessário, e retornam o tamanho do buffer que seria necessário, o que permite a detecção do truncamento e fornece um tamanho para a criação de um novo buffer que não será truncado. Eles foram criticados com base em serem supostamente ineficientes, encorajando o uso de strings C (em vez de alguma forma alternativa superior de string) e ocultando outros erros potenciais. Consequentemente, eles não foram incluídos na biblioteca GNU C (usada por software no Linux), embora sejam implementados nas bibliotecas C para OpenBSD, FreeBSD , NetBSD , Solaris , OS X e QNX , bem como em bibliotecas C alternativas para Linux, como o musl introduzido em 2011. A falta de suporte à biblioteca GNU C não impediu vários autores de software de usá-lo e empacotar um substituto, entre outros SDL , GLib , ffmpeg , rsync e até mesmo internamente no kernel Linux . Implementações de código aberto para essas funções estão disponíveis.

Às vezes, memcpyou memmovesão usados, pois podem ser mais eficientes do strcpyque porque não verificam repetidamente o NUL (isso é menos verdadeiro nos processadores modernos). Como eles precisam de um comprimento de buffer como parâmetro, a configuração correta desse parâmetro pode evitar estouros de buffer.

Como parte de seu Ciclo de Vida de Desenvolvimento de Segurança de 2004 , a Microsoft introduziu uma família de funções "seguras" incluindo strcpy_se strcat_s(junto com muitas outras). Essas funções foram padronizadas com algumas pequenas alterações como parte do C11 opcional (Anexo K) proposto pela ISO / IEC WDTR 24731. Essas funções executam várias verificações, incluindo se a sequência é muito longa para caber no buffer. Se as verificações falharem, uma função "manipulador de restrição de tempo de execução" especificada pelo usuário é chamada, o que geralmente aborta o programa. Algumas funções executam operações destrutivas antes de chamar o manipulador de restrição de tempo de execução; por exemplo, strcat_sdefine o destino para a string vazia, o que pode dificultar a recuperação de condições de erro ou depurá-las. Essas funções atraíram muitas críticas porque inicialmente eram implementadas apenas no Windows e, ao mesmo tempo, mensagens de alerta começaram a ser produzidas pelo Microsoft Visual C ++ sugerindo aos programadores que usassem essas funções em vez das padrão. Isso foi especulado por alguns como uma tentativa da Microsoft de prender os desenvolvedores em sua plataforma. Embora implementações de código aberto dessas funções estejam disponíveis, essas funções não estão presentes em bibliotecas C Unix comuns. A experiência com essas funções tem mostrado problemas significativos com sua adoção e erros no uso, então a remoção do Anexo K é proposta para a próxima revisão do padrão C. O uso de memset_stambém foi sugerido como uma forma de evitar otimizações indesejadas do compilador.

Veja também

Notas

Referências

links externos

  • Memcpy rápido em C , vários exemplos de codificação C para direcionar diferentes tipos de arquiteturas de instrução de CPU