Existe uma maneira de incluir um arquivo de texto inteiro como uma string em um programa C em tempo de compilação?
algo como:
file.txt:
This is a little text file
main.c:
#include <stdio.h> int main(void) { #blackmagicinclude("file.txt", content) /* equiv: char[] content = "This is\na little\ntext file"; */ printf("%s", content); }
obtendo um pequeno programa que imprime no stdout "Este é um pequeno arquivo de texto"
No momento, usei um script python hackish, mas é feio e limitado a apenas um nome de variável. Você pode me dizer outra maneira de fazer isso?
c
include
c-preprocessor
Brian Tompsett - 汤 莱恩
fonte
fonte
Respostas:
Eu sugiro usar (unix util) xxd para isso. você pode usá-lo assim
saídas:
fonte
xxd
, como a resposta diz. o nome da matriz é o nome do arquivo de entrada. se você estiver inserindo dados em vez de usar um arquivo de entrada, obterá uma lista de valores hexadecimais (sem a declaração da matriz ou a variável len).xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
A pergunta era sobre C, mas, se alguém tentar fazer isso com o C ++ 11, isso poderá ser feito com apenas pequenas alterações no arquivo de texto incluído, graças aos novos literais de cadeia de caracteres brutos :
Em C ++, faça o seguinte:
No arquivo de texto, faça o seguinte:
Portanto, deve haver apenas um prefixo na parte superior do arquivo e um sufixo no final dele. Entre elas, você pode fazer o que quiser, sem escapes especiais, desde que não precise da sequência de caracteres
)"
. Mas mesmo isso pode funcionar se você especificar seu próprio delimitador personalizado:fonte
1+R"...
como o delimitador inicial em vez deR"...
e depois colocar uma nova linha antesLine 1
. Isso transformará a expressão de uma matriz em um ponteiro, mas isso não é realmente um problema aqui, pois você está inicializando um ponteiro, não uma matriz.Você tem duas possibilidades:
\
),"
caracteres de escape e outros para fazer esse trabalho. É mais fácil escrever um pequeno programa para converter os bytes em uma sequência como'\xFF', '\xAB', ...., '\0'
(ou usar a ferramenta unixxxd
descrita por outra resposta, se você a tiver disponível!):Código:
(não testado). Então faça:
Onde data.h é gerado por
fonte
char my_file[] = { #include my_large_file.h };
Obrigado!bin2c
não é o mesmo bin2c do debian'shxtools
, cuidado!bin2c -H myoutput.h myinput1.txt myinputN.txt
ok, inspirado no post de Daemin, testei o seguinte exemplo simples:
a.data:
test.c:
gcc -E test.c output:
Portanto, está funcionando, mas exige dados entre aspas.
fonte
Eu gosto da resposta do kayahr. No entanto, se você não quiser tocar nos arquivos de entrada e se estiver usando o CMake , poderá adicionar as seqüências de caracteres de delimitação no arquivo. O seguinte código do CMake, por exemplo, copia os arquivos de entrada e agrupa o conteúdo adequadamente:
Em seguida, inclua no c ++ assim:
fonte
Você pode fazer isso usando
objcopy
:Agora você tem um arquivo de objeto que pode ser vinculado ao seu executável, que contém símbolos para o início, fim e tamanho do conteúdo
myfile.txt
.fonte
Você precisa do meu
xtr
utilitário, mas pode fazê-lo com umbash script
. Este é um script que eu chamobin2inc
. O primeiro parâmetro é o nome do resultantechar[] variable
. O segundo parâmetro é o nome dofile
. A saída é Cinclude file
com o conteúdo do arquivo codificado (em minúsculashex
) como o nome da variável fornecido. Ochar array
ézero terminated
, e o comprimento dos dados é armazenado em$variableName_length
VOCÊ PODE OBTER XTR AQUI xtr (eXTRapolator de caracteres) é GPLV3
fonte
Se você estiver disposto a recorrer a alguns truques sujos, poderá ser criativo com literais de string brutos e
#include
para certos tipos de arquivos.Por exemplo, digamos que eu queira incluir alguns scripts SQL para SQLite no meu projeto e que eu queira obter destaque de sintaxe, mas não quero nenhuma infraestrutura de construção especial. Eu posso ter este arquivo
test.sql
que é SQL válido para SQLite, onde--
inicia um comentário:E então, no meu código C ++, posso ter:
A saída é:
Ou, para incluir algum código Python de um arquivo
test.py
que é um script Python válido (porque#
inicia um comentário no Python epass
não funciona):E então no código C ++:
Qual saída:
Deve ser possível executar truques semelhantes para vários outros tipos de código que você pode querer incluir como uma string. Se é uma boa ideia ou não, não tenho certeza. É uma espécie de truque, mas provavelmente não é algo que você deseja em um código de produção real. Pode ser bom para um projeto de hack de fim de semana.
fonte
Reimplementei o xxd no python3, corrigindo todos os aborrecimentos do xxd:
unsigned
na matriz.Aqui está o script, filtrado por si só, para que você possa ver o que ele faz:
pyxxd.c
Uso (extrai o script):
fonte
O que pode funcionar é se você fizer algo como:
É claro que você terá que ter cuidado com o que está realmente no arquivo , certificando-se de que não haja aspas duplas, que todos os caracteres apropriados sejam escapados etc.
Portanto, pode ser mais fácil se você apenas carregar o texto de um arquivo em tempo de execução ou incorporar o texto diretamente no código.
Se você ainda quisesse o texto em outro arquivo, poderia tê-lo lá, mas ele teria que ser representado lá como uma string. Você usaria o código como acima, mas sem aspas duplas. Por exemplo:
file.txt
main.cpp
Então, basicamente, ter uma string de estilo C ou C ++ em um arquivo de texto que você incluir. Isso tornaria o código mais limpo, porque não há muito texto no início do arquivo.
fonte
Mesmo que isso possa ser feito em tempo de compilação (acho que não em geral), o texto provavelmente será o cabeçalho pré-processado, e não o conteúdo dos arquivos literalmente. Espero que você precise carregar o texto do arquivo em tempo de execução ou fazer um trabalho desagradável de cortar e colar.
fonte
A resposta de Hasturkun usando a opção xxd -i é excelente. Se você deseja incorporar o processo de conversão (texto -> arquivo de inclusão hexadecimal) diretamente na sua compilação, a ferramenta / biblioteca hexdump.c adicionou recentemente um recurso semelhante à opção -i do xxd (ele não fornece o cabeçalho completo - você precisa para fornecer a definição da matriz de caracteres, mas com a vantagem de permitir que você escolha o nome da matriz de caracteres):
http://25thandclement.com/~william/projects/hexdump.c.html
Sua licença é muito mais "padrão" que o xxd e é muito liberal - um exemplo de como usá-lo para incorporar um arquivo init em um programa pode ser visto nos arquivos CMakeLists.txt e schema.c aqui:
https://github.com/starseeker/tinyscheme-cmake
Existem prós e contras na inclusão de arquivos gerados nas árvores de origem e nos utilitários de empacotamento - como lidar com isso dependerá dos objetivos e necessidades específicos do seu projeto. O hexdump.c abre a opção de empacotamento para este aplicativo.
fonte
Eu acho que não é possível apenas com o compilador e o pré-processador. O gcc permite isso:
Mas infelizmente não é isso:
O erro é:
fonte
/etc/hostname
como uma maneira de incorporar o nome da máquina de construção na string, que (mesmo que funcionasse) não seria portátil, já que o Mac OS X não possui um arquivo/etc/hostname
. Observe que o uso de nomes de macro que começam com um sublinhado seguido por uma letra maiúscula está usando um nome reservado para a implementação, que é A Bad Thing ™.Por que não vincular o texto ao programa e usá-lo como uma variável global! Aqui está um exemplo. Estou pensando em usar isso para incluir arquivos de sombreador Open GL em um executável, pois os sombreadores GL precisam ser compilados para a GPU em tempo de execução.
fonte
Eu tive problemas semelhantes e, para arquivos pequenos, a solução de Johannes Schaub acima mencionada funcionou como um encanto para mim.
No entanto, para arquivos um pouco maiores, houve problemas com o limite da matriz de caracteres do compilador. Portanto, escrevi um pequeno aplicativo de codificador que converte o conteúdo do arquivo em uma matriz de caracteres 2D de pedaços de tamanho igual (e possivelmente preenchendo zeros). Produz arquivos de texto de saída com dados de matriz 2D como este:
onde 4 é realmente uma variável MAX_CHARS_PER_ARRAY no codificador. O arquivo com o código C resultante, chamado, por exemplo "main_js_file_data.h", pode ser facilmente incorporado ao aplicativo C ++, por exemplo:
Aqui está o código fonte do codificador:
fonte
Esse problema estava me irritando e o xxd não funciona no meu caso de uso, porque fez a variável chamada algo como __home_myname_build_prog_cmakelists_src_autogen quando tentei fazer o script, então criei um utilitário para resolver esse problema exato:
https://github.com/Exaeta/brcc
Ele gera um arquivo de origem e de cabeçalho e permite definir explicitamente o nome de cada variável para que você possa usá-los via std :: begin (nome da matriz) e std :: end (nome da matriz).
Eu o incorporei no meu projeto cmake da seguinte forma:
Com pequenos ajustes, acho que também poderia funcionar para C.
fonte
em xh
em main.c
deveria fazer o trabalho.
fonte