149 votes

"#inclure" un fichier texte dans un programme C comme un char[]

Existe-t-il un moyen d'inclure un fichier texte entier sous forme de chaîne dans un programme C au moment de la compilation ?

quelque chose comme :

  • 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);
    }

obtenir un petit programme qui imprime sur stdout "Ceci est un petit fichier texte"

Pour le moment, j'ai utilisé un script pirate de python, mais c'est moche et limité à un seul nom de variable, pouvez-vous me dire une autre façon de le faire ?

148voto

Hasturkun Points 18653

Je suggère d'utiliser (utilitaire unix) xxd pour cela. vous pouvez l'utiliser comme suit

$ echo hello world > a
$ xxd -i a

sorties :

unsigned char a[] = {
  0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;

124voto

kayahr Points 4326

La question portait sur le C, mais si quelqu'un essaie de le faire avec le C++11, il peut le faire en modifiant peu le fichier texte inclus grâce à la nouvelle fonction chaînes de caractères brutes :

En C++, faites ceci :

const char *s =
#include "test.txt"
;

Dans le fichier texte, faites ceci :

R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"

Il ne doit donc y avoir qu'un préfixe en début de fichier et un suffixe en fin de fichier. Entre les deux, vous pouvez faire ce que vous voulez, aucun échappement spécial n'est nécessaire tant que la séquence de caractères n'est pas nécessaire. )" . Mais même cela peut fonctionner si vous spécifiez votre propre délimiteur personnalisé :

R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="

15voto

Martin R. Points 581

J'aime la réponse de kayahr. Si vous ne voulez pas toucher aux fichiers d'entrée cependant, et si vous utilisez CMake vous pouvez ajouter les séquences de caractères délimiteurs dans le fichier. Le code CMake suivant, par exemple, copie les fichiers d'entrée et enveloppe leur contenu en conséquence :

function(make_includable input_file output_file)
    file(READ ${input_file} content)
    set(delim "for_c++_include")
    set(content "R\"${delim}(\n${content})${delim}\"")
    file(WRITE ${output_file} "${content}")
endfunction(make_includable)

# Use like
make_includable(external/shaders/cool.frag generated/cool.frag)

Puis inclure dans c++ comme ceci :

constexpr char *test =
#include "generated/cool.frag"
;

14voto

Vous avez deux possibilités :

  1. Utiliser les extensions du compilateur et du lieur pour convertir un fichier en fichier binaire, avec des symboles appropriés pointant vers le début et la fin des données binaires. Voir cette réponse : Inclure le fichier binaire avec le linker GNU ld script .
  2. Convertissez votre fichier en une séquence de constantes de caractères qui peuvent initialiser un tableau. Notez que vous ne pouvez pas simplement faire "" et couvrir plusieurs lignes. Vous aurez besoin d'un caractère de continuation de ligne ( \ ), s'échapper " les personnages et les autres pour que cela fonctionne. Il est plus facile d'écrire un petit programme pour convertir les octets en une séquence du genre '\xFF', '\xAB', ...., '\0' (ou utilisez l'outil unix xxd décrite par une autre réponse, si vous l'avez à disposition !)

Code :

#include <stdio.h>

int main() {
    int c;
    while((c = fgetc(stdin)) != EOF) {
        printf("'\\x%X',", (unsigned)c);
    }
    printf("'\\0'"); // put terminating zero
}

(non testé). Ensuite, faites :

char my_file[] = {
#include "data.h"
};

Où data.h est généré par

cat file.bin | ./bin2c > data.h

9voto

Ilya Points 2279

Ok, inspiré par Daemin post j'ai testé l'exemple simple suivant :

a.données :

"this is test\n file\n"

test.c :

int main(void)
{
    char *test = 
#include "a.data"
    ;
    return 0;
}

gcc -E test.c sortie :

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.c"

int main(void)
{
    char *test =
# 1 "a.data" 1
"this is test\n file\n"
# 6 "test.c" 2
    ;
    return 0;
}

Donc ça marche mais il faut des données entourées de guillemets.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X