invalid character in source — Como Resolver em Zig
O Que Este Erro Significa
O erro invalid character in source ocorre quando o compilador Zig encontra um caractere no código-fonte que não é permitido fora de strings e comentários. Zig é rigoroso sobre quais caracteres são válidos no código-fonte: apenas ASCII imprimível (exceto certas exceções), newlines e tabs em contextos específicos. Caracteres Unicode fora de strings literais, caracteres de controle invisíveis e marcas BOM (Byte Order Mark) são rejeitados.
Causas Comuns
1. BOM (Byte Order Mark) no Início do Arquivo
Alguns editores (especialmente no Windows) adicionam um caractere BOM (U+FEFF) invisível no início de arquivos UTF-8:
// O arquivo começa com bytes invisíveis: EF BB BF
const std = @import("std"); // ERRO: invalid character
2. Caracteres Unicode em Identificadores
pub fn main() void {
const preço = 42; // ERRO: 'ç' não é ASCII válido em identificadores
_ = preço;
}
3. Aspas Inteligentes (Smart Quotes)
Copiando código de editores de texto ou páginas web, você pode acabar com aspas curvas:
pub fn main() void {
const nome = "Zig"; // ERRO: aspas curvas " " ao invés de retas " "
_ = nome;
}
4. Espaço Não-Quebrável (Non-Breaking Space)
O caractere U+00A0 (non-breaking space) se parece com um espaço normal, mas não é:
pub fn main() void {
const x = 42; // ERRO: espaço invisível errado entre 'const' e 'x'
_ = x;
}
5. Tab em Local Inadequado
Zig tem regras específicas sobre onde tabs são permitidos. O zig fmt converte tabs para espaços:
pub fn main() void {
const x = 42; // Tab para indentação — pode causar aviso
_ = x;
}
6. Caracteres de Controle Copiados Acidentalmente
pub fn main() void {
const x = 42; // Pode conter Ctrl+M (^M / \r) em arquivos do Windows
_ = x;
}
Como Corrigir
Solução 1: Remover BOM do Arquivo
No Linux/macOS:
# Verificar se o arquivo tem BOM
file src/main.zig
# Remover BOM
sed -i '1s/^\xEF\xBB\xBF//' src/main.zig
No VS Code: abra o arquivo, clique em “UTF-8 with BOM” no canto inferior direito e selecione “UTF-8” (sem BOM).
Solução 2: Usar Apenas ASCII em Identificadores
pub fn main() void {
const preco = 42; // Correto: 'preco' sem acentos
_ = preco;
}
Se precisar de texto com acentos, use strings:
const nome_display = "Preço"; // Unicode é permitido dentro de strings
Solução 3: Substituir Aspas Inteligentes
pub fn main() void {
const nome = "Zig"; // Correto: aspas retas
_ = nome;
}
Solução 4: Usar zig fmt
O formatador do Zig pode corrigir alguns desses problemas automaticamente:
zig fmt src/main.zig
Solução 5: Converter Fins de Linha
Converta \r\n (Windows) para \n (Unix):
# No Linux/macOS
dos2unix src/main.zig
# Ou com sed
sed -i 's/\r$//' src/main.zig
Solução 6: Reescrever o Arquivo
Se nada mais funcionar, crie um novo arquivo e copie apenas o texto visível:
# Copiar apenas caracteres ASCII imprimíveis + newlines
tr -cd '\11\12\15\40-\176' < src/main.zig > src/main_clean.zig
mv src/main_clean.zig src/main.zig
Como Prevenir
Configurar o Editor Corretamente
VS Code — adicione ao settings.json:
{
"files.encoding": "utf8",
"files.eol": "\n",
"editor.renderControlCharacters": true,
"files.trimTrailingWhitespace": true
}
Vim — adicione ao .vimrc:
set encoding=utf-8
set fileformat=unix
set list
Usar .editorconfig
Crie um arquivo .editorconfig no projeto:
[*.zig]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
Verificar com xxd ou hexdump
Para encontrar caracteres invisíveis problemáticos:
xxd src/main.zig | head -5
# Procure por bytes fora do range 20-7E (exceto 0A e 0D)
Caracteres Válidos no Código-Fonte Zig
- Identificadores: letras ASCII (
a-z,A-Z), dígitos (0-9), underscore (_) - Strings: qualquer sequência de bytes UTF-8 válida
- Comentários: qualquer sequência de bytes UTF-8 válida
- Whitespace: espaço (
0x20), newline (0x0A)
Perguntas Frequentes
Posso usar nomes de variáveis com acentos em Zig de alguma forma?
Não diretamente como identificadores — Zig só permite ASCII em nomes de variáveis, funções, tipos e constantes. Isso é uma decisão deliberada de design para garantir portabilidade e evitar ambiguidades de encoding. A alternativa aceita pela comunidade é usar o equivalente sem acento (por exemplo, preco em vez de preço, configuracao em vez de configuração). Para strings e comentários, Unicode é totalmente suportado — você pode ter const nome_display = "Preço" e comentários em português com todos os acentos. O formatador zig fmt também ajuda a identificar problemas de encoding ao formatar o arquivo.
Por que o erro de caractere inválido às vezes aponta para a linha errada?
Caracteres invisíveis como BOM (U+FEFF) ou non-breaking spaces (U+00A0) podem causar essa confusão. O BOM, por exemplo, é inserido antes do primeiro caractere do arquivo, então o compilador reporta o erro na linha 1, coluna 1, mas você não vê nada de errado ao olhar o arquivo no editor. A ferramenta xxd é especialmente útil nesses casos: execute xxd src/main.zig | head -3 e verifique se o arquivo começa com ef bb bf (que é a representação hexadecimal do BOM UTF-8). Se começar com esses bytes, use sed ou a configuração do editor para salvar sem BOM.
Como o zig fmt trata caracteres inválidos?
O zig fmt pode resolver alguns problemas de encoding, como normalizar fins de linha de \r\n para \n, mas não consegue adivinhar qual caractere Unicode você quis usar em um identificador. Para BOM e non-breaking spaces em whitespace, o formatador geralmente consegue corrigir. Para aspas inteligentes ou caracteres em identificadores, você precisará fazer a correção manualmente antes de executar zig fmt. Uma boa prática é sempre executar zig fmt como parte do pipeline de CI para garantir que o código está devidamente formatado.
Erros Relacionados
- expected expression — Expressão esperada pelo compilador
- expected ‘;’ — Ponto e vírgula faltando
- expected ‘}’ — Chave de fechamento faltando