Texto chega de usuários, arquivos e da linha de comando como caracteres. "42" são três bytes - '4', '2', '\0' - e nada nele é o número 42 até você converter. O C oferece duas gerações de funções de conversão: as curtas e antigas, que não conseguem reportar erros, e as mais longas, que conseguem. Esta página mostra as duas e explica por que programas reais usam o segundo conjunto.
A família antiga: atoi, atol, atof
Elas se leem como os seus nomes: ASCII para int, para long, para double. Um argumento, um resultado.
Espaços em branco iniciais são pulados, um sinal opcional é lido, os dígitos são consumidos e tudo depois é ignorado. Isso é conveniente até a entrada estar errada:
Os três imprimem 0. Não há código de retorno, nem sinalizador, nem forma de perguntar "isso funcionou?" - e um valor que estoura o int é comportamento indefinido em vez de um erro reportado. Para um literal fixo num programa de brinquedo isso é tolerável. Para qualquer coisa que uma pessoa ou um arquivo possa fornecer, é um gerador silencioso de bugs.
A ferramenta certa: strtol
O strtol (string to long) é a mesma conversão com dois canais para reportar o que aconteceu.
long strtol(const char *text, char **endptr, int base);
endptr recebe o primeiro caractere que a função não consumiu. base é a base numérica - use 10, ou 0 para deixar o prefixo do próprio literal decidir (0x para hexadecimal, 0 inicial para octal).
Ler o endptr responde às perguntas que o atoi não responde:
end == inputsignifica que nada foi convertido - o texto não começava com um número.*end != '\0'significa que havia conteúdo sobrando. Se isso é um erro, você decide: tudo bem ao interpretar"42 macas", e é um problema quando a linha inteira deveria ser um número.
O estouro é reportado à parte, pelo errno. Vale escrever o idioma completo e correto uma vez e reutilizá-lo:
Três detalhes tornam isso correto. O errno = 0 antes da chamada importa porque a biblioteca só atribui o errno; ela nunca o limpa, então um valor velho de uma chamada anterior seria lido como falha desta chamada. O strtol devolve long, que pode ser mais largo que int, então a verificação de intervalo contra INT_MIN/INT_MAX é separada do ERANGE. E devolver o sucesso como status enquanto entrega o valor por um ponteiro é como funções em C reportam "ou um valor, ou uma falha" - o valor de retorno não pode fazer os dois trabalhos.
strtoul é a contraparte sem sinal, e strtoll/strtoull tratam long long.
Outras bases
A base 16 lê hexadecimal; a base 0 inspeciona o prefixo e decide sozinha.
A base 0 é uma armadilha num caso específico: um decimal com zero à esquerda como "012" é lido como octal e sai como 10. Se sua entrada é decimal, diga 10 explicitamente.
Ponto flutuante: strtod
O strtod tem a mesma forma para double, e o atof tem o mesmo defeito do atoi.
O strtod também aceita notação científica ("1.5e3"), floats hexadecimais e as palavras "inf" e "nan". O locale afeta o separador decimal, o que surpreende quem lê arquivos escritos em outro lugar - no locale padrão "C" o separador é sempre um ponto.
Números para texto: snprintf
No caminho inverso, o snprintf é a resposta padrão. Ele escreve no máximo o tamanho que você indicar, sempre termina a string, e devolve o comprimento de que o resultado completo precisaria.
O valor de retorno é a verificação de truncamento. Se ele for maior ou igual ao tamanho do buffer, o texto não coube:
Duas coisas às quais não recorrer: itoa não faz parte do C padrão, então código que o usa não compila em todo lugar; e sprintf é o snprintf sem o limite de tamanho, o que significa que ele vai escrever além do fim do seu buffer sem reclamar.
Caracteres isolados e o '0'
Os caracteres de dígito de '0' a '9' têm garantia de serem consecutivos, então uma simples subtração converte entre um caractere de dígito e o seu valor.
Só os dígitos se comportam assim - letras não precisam ser consecutivas, então c - 'a' não é portável para aritmética no alfabeto. Proteja a subtração com isdigit antes de confiar nela:
A conversão para unsigned char é obrigatória pela mesma razão vista em strings: as funções de <ctype.h> são indefinidas para argumentos negativos, e um char puro pode ter sinal.
Qual função usar
- Texto de um usuário, de um arquivo ou do
argv→strtol/strtodcom a verificação completa. - Um literal que você mesmo escreveu e controla →
atoié aceitável, ainda que sem graça. - Número para dentro de um buffer →
snprintf, e confira o valor de retorno. - Um único caractere de dígito → subtraia
'0', depois doisdigit. - Nunca →
gets,sprintf,itoa.
Perguntas frequentes
Como converter uma string em int em C?
strtol(texto, &end, 10) é a resposta correta: ela devolve o valor, aponta end para o primeiro caractere que não consumiu e reporta estouro através do errno. atoi(texto) é mais curto, mas devolve 0 tanto para "0" quanto para "ola", sem como distinguir os dois.
O que há de errado com o atoi em C?
Ele não consegue reportar falha. atoi("abc") devolve 0, indistinguível de um zero de verdade, e o estouro é comportamento indefinido em vez de um erro reportado. Use strtol sempre que o texto vier de um usuário, de um arquivo ou de um argumento de linha de comando.
Como converter um int em string em C?
snprintf(buf, sizeof buf, "%d", n). É padrão, limitado pelo tamanho do buffer, e devolve o número de caracteres de que o resultado completo precisaria - então um valor de retorno igual ou maior que sizeof buf avisa que o texto foi truncado. itoa não é C padrão.
Como transformar o caractere '7' no número 7 em C?
Subtraia '0': int digito = c - '0';. Os caracteres de dígito são consecutivos em todo conjunto de caracteres do C, então a subtração dá de 0 a 9. Proteja isso com isdigit((unsigned char)c) antes, já que a aritmética não faz sentido para qualquer outra coisa.