"#Include" un fichier texte dans un programme C sous forme de caractère []

130

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
  • principal 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 python hackish, mais c'est moche et limité à un seul nom de variable, pouvez-vous me dire une autre façon de le faire?

Brian Tompsett - 汤 莱恩
la source
Jetez un oeil ici pour lire un fichier dans un char []. /programming/410943/reading-a-text-file-into-an-array-in-c Voici quelques conseils pour utiliser les macros du préprocesseur C. http://gcc.gnu.org/onlinedocs/cpp/Macros.html
Daniel A. White
3
Pourquoi veux-tu faire cela? Pourquoi ne pas lire le fichier au moment de l'exécution? (Réponse: peut-être parce qu'il est difficile de savoir où se trouve le fichier au moment de l'exécution, ou peut-être parce qu'il ne devrait y avoir qu'un seul fichier à installer.)
Jonathan Leffler
ou peut-être que le fichier texte n'est disponible qu'au moment de la compilation, comme le code source.
TMS
1
Parfois, vous souhaitez accéder aux données en tant que fichiers séparés au moment du développement, mais que le contenu est compilé dans votre binaire. L'exemple exécute un serveur Web sur un Arduino qui n'a pas accès au stockage local. Vous souhaitez conserver vos fichiers html séparés pour les modifier, mais au moment de la compilation, ils doivent exister sous forme de chaînes dans votre source.
Geordie

Réponses:

134

Je suggérerais d'utiliser (unix util) xxd pour cela. tu peux l'utiliser comme ça

$ echo hello world > a
$ xxd -i a

les sorties:

unsigned char a[] = {
  0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
Hasturkun
la source
18
Juste une note: le char [] créé par xxd n'est pas terminé par NULL! donc je fais $ xxd -i <file.txt> file.xxd $ echo ', 0' >> file.xxd et dans le fichier main.c char file_content [] = {#include "file.xxd"};
2
Je n'ai jamais su pour xxd. C'est génial!
1
@eSKay: cela vient directement de la sortie de xxd, comme le dit la réponse. le nom du tableau est le nom du fichier d'entrée. si vous transférez des données au lieu d'utiliser un fichier d'entrée, vous obtiendrez une liste de valeurs hexadécimales à la place (sans la déclaration de tableau ou la variable len).
Hasturkun
4
C'est extrêmement utile lors de l'incorporation de shaders GLSL.
linello
5
Une autre façon d'ajouter la terminaison 0x00 au code C produit xxd:xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
vleo
104

La question concernait C mais au cas où quelqu'un essaie de le faire avec C ++ 11, cela peut être fait avec seulement de petites modifications dans le fichier texte inclus grâce aux nouveaux littéraux de chaîne bruts :

En C ++, procédez comme suit:

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

Dans le fichier texte, procédez comme suit:

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

Il ne doit donc y avoir qu'un préfixe en haut du fichier et un suffixe à la fin de celui-ci. Entre cela, vous pouvez faire ce que vous voulez, aucun échappement spécial n'est nécessaire tant que vous n'avez pas besoin de la séquence de caractères )". 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)====="
Kayahr
la source
5
Merci, j'ai choisi la méthode proposée ici pour intégrer de longs fragments de sql dans mon code C ++ 11. Cela me permet de garder le SQL proprement séparé dans ses propres fichiers et de les modifier avec une vérification de syntaxe appropriée, une mise en évidence, etc.
YitzikC
1
C'est vraiment proche de ce que je veux. Surtout le délimiteur défini par l'utilisateur. Très utile. Je veux aller plus loin: existe-t-il un moyen de supprimer complètement le préfixe R "(et le suffixe)" du fichier que vous souhaitez inclure? J'ai essayé de définir deux fichiers appelés bra.in et ket.in avec le préfixe et le suffixe, notamment bra.in, file.txt et ket.in un par un. Mais le compilateur évalue le contenu de bra.in (qui est juste R "() avant d'inclure le fichier suivant. Donc il se plaindra. S'il vous plaît laissez-moi savoir si quelqu'un sait comment obtenir le préfixe et le suffixe de file.txt. Merci.
TMS
Je suppose que C ++ n'autoriserait pas R "(<newline> #include ...)"? Ce serait bien d'avoir le fichier en cours de compilation au moment de l'ingestion pour ne nécessiter aucun encodage ... c'est-à-dire directement json ou xml ou csv ou autre chose ..
Brian Chrisman
Vous pouvez rendre le texte du littéral brut un peu plus lisible si vous utilisez 1+R"...comme délimiteur de départ au lieu de R"..., puis ajoutez une nouvelle ligne avant Line 1. Cela transformera l'expression d'un tableau en pointeur, mais ce n'est pas vraiment un problème ici, puisque vous initialisez un pointeur, pas un tableau.
Ruslan le
14

Vous avez deux possibilités:

  1. Utilisez les extensions du compilateur / éditeur de liens pour convertir un fichier en fichier binaire, avec les symboles appropriés pointant vers le début et la fin des données binaires. Voir cette réponse: Incluez le fichier binaire avec le script de l'éditeur de liens GNU ld .
  2. Convertissez votre fichier en une séquence de constantes de caractères pouvant initialiser un tableau. Notez que vous ne pouvez pas simplement faire "" et couvrir plusieurs lignes. Vous auriez besoin d'un caractère de continuation de ligne ( \), de "caractères d' échappement et d'autres pour que cela fonctionne. Plus facile d'écrire simplement un petit programme pour convertir les octets en une séquence comme '\xFF', '\xAB', ...., '\0'(ou d'utiliser l'outil unix xxddécrit par une autre réponse, si vous l'avez disponible!):

Code:

#include <stdio.h>

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

(pas testé). Alors fais:

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

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

cat file.bin | ./bin2c > data.h
Johannes Schaub - litb
la source
1
la dernière ligne devrait probablement lire "cat file.bin | ./bin2c> data.h" ou "./bin2c <file.bin> data.h"
Hasturkun
J'ai utilisé codeproject.com/Tips/845393/... pour créer un fichier hexadécimal (sous Windows) à partir d'un binaire, puis j'ai utilisé votre suggestion de char my_file[] = { #include my_large_file.h };Merci!
Someone Somewhere
bin2cn'est pas le même bin2c que celui de Debian hxtools, attention
ThorSummoner
ou si c'est le cas, l'invocation est beaucoup plus étrange maintenant:bin2c -H myoutput.h myinput1.txt myinputN.txt
ThorSummoner
9

ok, inspiré du post de Daemin, 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;
}

Sortie gcc -E test.c:

# 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;
}

Cela fonctionne donc mais nécessite des données entre guillemets.

Il y a
la source
C'est ce à quoi je faisais allusion dans la dernière partie de ma réponse.
Daemin
citation, ou peu importe son nom, pardonnez mon anglais
Ilya
Cela nécessite que les données soient échappées en C. Je ne pense pas que ce soit ce que recherche le poste. Si cela avait une sorte de macro d'inclusion qui échappait au contenu du fichier, ce serait très bien.
Brian Chrisman
8

J'aime la réponse de Kayahr. Cependant, si vous ne souhaitez pas toucher les fichiers d'entrée , et si vous utilisez CMake , vous pouvez ajouter les séquences de caractères de délimitation sur le fichier. Le code CMake suivant, par exemple, copie les fichiers d'entrée et encapsule 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)

Ensuite, incluez en c ++ comme ceci:

constexpr char *test =
#include "generated/cool.frag"
;
Martin R.
la source
5

Vous pouvez le faire en utilisant objcopy:

objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o

Vous avez maintenant un fichier objet que vous pouvez lier à votre exécutable qui contient des symboles pour le début, la fin et la taille du contenu à partir de myfile.txt.

John Zwinck
la source
1
pouvez-vous nous dire quels seront les noms des symboles?
Mark Ch
@MarkCh: selon la documentation, les noms de symboles sont générés à partir du nom de fichier d'entrée.
John Zwinck
Je suppose que cela ne fonctionnera pas sur les machines non x86-64, n'est-ce pas?
ThorSummoner
2

Vous avez besoin de mon xtrutilitaire mais vous pouvez le faire avec un fichier bash script. C'est un script que j'appelle bin2inc. Le premier paramètre est le nom du résultat char[] variable. Le deuxième paramètre est le nom du file. La sortie est C include fileavec le contenu du fichier codé (en minuscules hex) comme nom de variable donné. Le char arrayest zero terminatedet la longueur des données est stockée dans$variableName_length

#!/bin/bash

fileSize ()

{

    [ -e "$1" ]  && {

        set -- `ls -l "$1"`;

        echo $5;

    }

}

echo unsigned char $1'[] = {'
./xtr -fhex -p 0x -s ', ' < "$2";
echo '0x00'
echo '};';
echo '';
echo unsigned long int ${1}_length = $(fileSize "$2")';'

VOUS POUVEZ OBTENIR XTR ICI xtr (character eXTRapolator) est GPLV3


la source
2

Si vous êtes prêt à recourir à des astuces sales, vous pouvez faire preuve de créativité avec des littéraux de chaîne bruts et #includepour certains types de fichiers.

Par exemple, disons que je veux inclure des scripts SQL pour SQLite dans mon projet et que je veux obtenir une coloration syntaxique mais je ne veux pas d'infrastructure de construction spéciale. Je peux avoir ce fichier test.sqlqui est SQL valide pour SQLite où --commence un commentaire:

--x, R"(--
SELECT * from TestTable
WHERE field = 5
--)"

Et puis dans mon code C ++, je peux avoir:

int main()
{
    auto x = 0;
    const char* mysql = (
#include "test.sql"
    );

    cout << mysql << endl;
}

La sortie est:

--
SELECT * from TestTable
WHERE field = 5
--

Ou pour inclure du code Python à partir d'un fichier test.pyqui est un script Python valide (car #démarre un commentaire en Python et passest un no-op):

#define pass R"(
pass
def myfunc():
    print("Some Python code")

myfunc()
#undef pass
#define pass )"
pass

Et puis dans le code C ++:

int main()
{
    const char* mypython = (
#include "test.py"
    );

    cout << mypython << endl;
}

Qui produira:

pass
def myfunc():
    print("Some Python code")

myfunc()
#undef pass
#define pass

Il devrait être possible de jouer des tours similaires pour divers autres types de code que vous voudrez peut-être inclure sous forme de chaîne. Que ce soit une bonne idée ou non, je ne suis pas sûr. C'est une sorte de hack soigné, mais probablement pas quelque chose que vous voudriez dans un vrai code de production. Cela pourrait cependant convenir à un projet de hack du week-end.

mattnewport
la source
J'ai également utilisé cette approche pour mettre OpenGL Shaders dans des fichiers texte!
yano
1

J'ai réimplémenté xxd en python3, corrigeant tous les ennuis de xxd:

  • Correction de const
  • type de données de longueur de chaîne: int → size_t
  • Résiliation nulle (au cas où vous voudriez cela)
  • Compatible chaîne C: Drop unsignedsur le tableau.
  • Sortie plus petite et lisible, comme vous l'auriez écrit: l'ascii imprimable est sorti tel quel; les autres octets sont codés en hexadécimal.

Voici le script, filtré par lui-même, pour que vous puissiez voir ce qu'il fait:

pyxxd.c

#include <stddef.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

const char pyxxd[] =
"#!/usr/bin/env python3\n"
"\n"
"import sys\n"
"import re\n"
"\n"
"def is_printable_ascii(byte):\n"
"    return byte >= ord(' ') and byte <= ord('~')\n"
"\n"
"def needs_escaping(byte):\n"
"    return byte == ord('\\\"') or byte == ord('\\\\')\n"
"\n"
"def stringify_nibble(nibble):\n"
"    if nibble < 10:\n"
"        return chr(nibble + ord('0'))\n"
"    return chr(nibble - 10 + ord('a'))\n"
"\n"
"def write_byte(of, byte):\n"
"    if is_printable_ascii(byte):\n"
"        if needs_escaping(byte):\n"
"            of.write('\\\\')\n"
"        of.write(chr(byte))\n"
"    elif byte == ord('\\n'):\n"
"        of.write('\\\\n\"\\n\"')\n"
"    else:\n"
"        of.write('\\\\x')\n"
"        of.write(stringify_nibble(byte >> 4))\n"
"        of.write(stringify_nibble(byte & 0xf))\n"
"\n"
"def mk_valid_identifier(s):\n"
"    s = re.sub('^[^_a-z]', '_', s)\n"
"    s = re.sub('[^_a-z0-9]', '_', s)\n"
"    return s\n"
"\n"
"def main():\n"
"    # `xxd -i` compatibility\n"
"    if len(sys.argv) != 4 or sys.argv[1] != \"-i\":\n"
"        print(\"Usage: xxd -i infile outfile\")\n"
"        exit(2)\n"
"\n"
"    with open(sys.argv[2], \"rb\") as infile:\n"
"        with open(sys.argv[3], \"w\") as outfile:\n"
"\n"
"            identifier = mk_valid_identifier(sys.argv[2]);\n"
"            outfile.write('#include <stddef.h>\\n\\n');\n"
"            outfile.write('extern const char {}[];\\n'.format(identifier));\n"
"            outfile.write('extern const size_t {}_len;\\n\\n'.format(identifier));\n"
"            outfile.write('const char {}[] =\\n\"'.format(identifier));\n"
"\n"
"            while True:\n"
"                byte = infile.read(1)\n"
"                if byte == b\"\":\n"
"                    break\n"
"                write_byte(outfile, ord(byte))\n"
"\n"
"            outfile.write('\";\\n\\n');\n"
"            outfile.write('const size_t {}_len = sizeof({}) - 1;\\n'.format(identifier, identifier));\n"
"\n"
"if __name__ == '__main__':\n"
"    main()\n"
"";

const size_t pyxxd_len = sizeof(pyxxd) - 1;

Utilisation (ceci extrait le script):

#include <stdio.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

int main()
{
    fwrite(pyxxd, 1, pyxxd_len, stdout);
}
user2394284
la source
1

Ce qui pourrait fonctionner, c'est si vous faites quelque chose comme:

int main()
{
    const char* text = "
#include "file.txt"
";
    printf("%s", text);
    return 0;
}

Bien sûr, vous devrez faire attention à ce qui se trouve réellement dans le fichier , en vous assurant qu'il n'y a pas de guillemets doubles, que tous les caractères appropriés sont échappés, etc.

Par conséquent, il peut être plus facile de charger simplement le texte d'un fichier au moment de l'exécution ou d'incorporer le texte directement dans le code.

Si vous vouliez toujours le texte dans un autre fichier, vous pourriez l'avoir là-dedans, mais il devrait y être représenté sous forme de chaîne. Vous utiliseriez le code comme ci-dessus, mais sans les guillemets. Par exemple:

file.txt

"Something evil\n"\
"this way comes!"

main.cpp

int main()
{
    const char* text =
#include "file.txt"
;
    printf("%s", text);
    return 0;
}

Donc, en gros, avoir une chaîne de style C ou C ++ dans un fichier texte que vous incluez. Cela rendrait le code plus net car il n'y a pas autant de texte au début du fichier.

Daemin
la source
3
Bonne idée mais ça ne marchera pas, soit vous avez une erreur car le littéral inclut une nouvelle ligne, soit la partie #include sera lue comme une chaîne et non exécutée, damné si vous le faites et damné si vous ne le faites pas. .
Motti
1
@Motti: d'accord - tel qu'écrit, syntaxiquement invalide C. L'idée est intéressante - le pré-processeur C est logiquement une phase distincte - mais la pratique est qu'il ne décolle pas car chaque ligne du fichier inclus aurait pour finir par une barre oblique inverse, etc.
Jonathan Leffler
2
Humm. Il me semble que vous ne devriez pas avoir besoin de la barre oblique inverse, car la plupart des compilateurs concaténeront des chaînes adjecentes ensemble
EvilTeach
le problème avec cette réponse est ... si c'était aussi simple que cela, je ne pense pas que l'OP aurait jamais posé la question! -1 parce que la présence de cette réponse encourage légèrement les gens à perdre leur temps à essayer quelque chose qui ne fonctionne pas. Je pense que nous pourrions supprimer le vote défavorable si vous remplaçiez "Ce qui pourrait fonctionner" par "Pour référence, cela ne fonctionne pas"
Mark Ch
@JonathanLeffler Une fois le préprocesseur exécuté, il doit être valide en C ou C ++ en fonction du formatage de file.txt.
Daemin
0

Même si cela peut être fait au moment de la compilation (je ne pense pas que cela soit possible en général), le texte serait probablement l'en-tête prétraité plutôt que le contenu des fichiers textuellement. J'espère que vous devrez charger le texte du fichier au moment de l'exécution ou faire un mauvais travail de couper-coller.

Daniel Paull
la source
0

La réponse de Hasturkun en utilisant l'option xxd -i est excellente. Si vous souhaitez incorporer le processus de conversion (texte -> fichier d'inclusion hexadécimal) directement dans votre build, l'outil / bibliothèque hexdump.c a récemment ajouté une fonctionnalité similaire à l'option -i de xxd (elle ne vous donne pas l'en-tête complet - vous avez besoin pour fournir la définition du tableau char - mais cela a l'avantage de vous permettre de choisir le nom du tableau char):

http://25thandclement.com/~william/projects/hexdump.c.html

Sa licence est beaucoup plus "standard" que xxd et est très libérale - un exemple de son utilisation pour intégrer un fichier init dans un programme peut être vu dans les fichiers CMakeLists.txt et scheme.c ici:

https://github.com/starseeker/tinyscheme-cmake

Il y a des avantages et des inconvénients à inclure les fichiers générés dans les arborescences sources et à regrouper les utilitaires - la façon de les gérer dépendra des objectifs et des besoins spécifiques de votre projet. hexdump.c ouvre l'option de regroupement pour cette application.

starseeker
la source
0

Je pense que ce n'est pas possible avec le compilateur et le préprocesseur seuls. gcc permet ceci:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               define hostname my_dear_hostname
                hostname
            )
            "\n" );

Mais malheureusement pas ça:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               include "/etc/hostname"
            )
            "\n" );

L'erreur est:

/etc/hostname: In function init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"
pas un utilisateur
la source
J'ai regardé, comme tu m'as demandé de regarder. Je ne vois aucune nouvelle information dans votre réponse (information qui ne figure pas dans d'autres réponses), au-delà d'une référence à /etc/hostnameune manière d'incorporer le nom de la machine de construction dans la chaîne, ce qui (même si cela fonctionnait) ne serait pas portable car Mac OS X n'a ​​pas de fichier /etc/hostname. Notez que l'utilisation de noms de macro commençant par un trait de soulignement suivi d'une lettre majuscule consiste à utiliser un nom réservé à l'implémentation, qui est A Bad Thing ™.
Jonathan Leffler
0

Pourquoi ne pas lier le texte au programme et l'utiliser comme variable globale! Voici un exemple. J'envisage de l'utiliser pour inclure les fichiers de shader Open GL dans un exécutable car les shaders GL doivent être compilés pour le GPU au moment de l'exécution.

TechDragon
la source
0

J'ai eu des problèmes similaires, et pour les petits fichiers, la solution susmentionnée de Johannes Schaub a fonctionné comme un charme pour moi.

Cependant, pour les fichiers un peu plus volumineux, il a rencontré des problèmes avec la limite de tableau de caractères du compilateur. Par conséquent, j'ai écrit une petite application d'encodeur qui convertit le contenu du fichier en un tableau de caractères 2D de morceaux de taille égale (et éventuellement de zéros de remplissage). Il produit des fichiers texte de sortie avec des données de tableau 2D comme ceci:

const char main_js_file_data[8][4]= {
    {'\x69','\x73','\x20','\0'},
    {'\x69','\x73','\x20','\0'},
    {'\x61','\x20','\x74','\0'},
    {'\x65','\x73','\x74','\0'},
    {'\x20','\x66','\x6f','\0'},
    {'\x72','\x20','\x79','\0'},
    {'\x6f','\x75','\xd','\0'},
    {'\xa','\0','\0','\0'}};

où 4 est en fait une variable MAX_CHARS_PER_ARRAY dans l'encodeur. Le fichier avec le code C résultant, appelé par exemple "main_js_file_data.h" peut alors facilement être inséré dans l'application C ++, par exemple comme ceci:

#include "main_js_file_data.h"

Voici le code source de l'encodeur:

#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>


#define MAX_CHARS_PER_ARRAY 2048


int main(int argc, char * argv[])
{
    // three parameters: input filename, output filename, variable name
    if (argc < 4)
    {
        return 1;
    }

    // buffer data, packaged into chunks
    std::vector<char> bufferedData;

    // open input file, in binary mode
    {    
        std::ifstream fStr(argv[1], std::ios::binary);
        if (!fStr.is_open())
        {
            return 1;
        }

        bufferedData.assign(std::istreambuf_iterator<char>(fStr), 
                            std::istreambuf_iterator<char>()     );
    }

    // write output text file, containing a variable declaration,
    // which will be a fixed-size two-dimensional plain array
    {
        std::ofstream fStr(argv[2]);
        if (!fStr.is_open())
        {
            return 1;
        }
        const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
        fStr << "const char " << argv[3] << "[" << numChunks           << "]"    <<
                                            "[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
        std::size_t count = 0;
        fStr << std::hex;
        while (count < bufferedData.size())
        {
            std::size_t n = 0;
            fStr << "{";
            for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
            {
                fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
            }
            // fill missing part to reach fixed chunk size with zero entries
            for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
            {
                fStr << "'\\0',";
            }
            fStr << "'\\0'}";
            if (count < bufferedData.size())
            {
                fStr << ",\n";
            }
        }
        fStr << "};\n";
    }

    return 0;
}
Volzotan
la source
0

Ce problème m'irritait et xxd ne fonctionne pas pour mon cas d'utilisation car il a fait de la variable appelée quelque chose comme __home_myname_build_prog_cmakelists_src_autogen lorsque j'ai essayé de l'écrire, j'ai donc créé un utilitaire pour résoudre ce problème exact:

https://github.com/Exaeta/brcc

Il génère un fichier source et un fichier d'en-tête et vous permet de définir explicitement le nom de chaque variable afin que vous puissiez les utiliser via std :: begin (arrayname) et std :: end (arrayname).

Je l'ai incorporé dans mon projet cmake comme ceci:

add_custom_command(
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.hpp ${CMAKE_CURRENT_BINARY_DIR}/binary_resources.cpp
  COMMAND brcc ${CMAKE_CURRENT_BINARY_DIR}/binary_resources RGAME_BINARY_RESOURCES_HH txt_vertex_shader ${CMAKE_CURRENT_BINARY_DIR}/src/vertex_shader1.glsl
  DEPENDS src/vertex_shader1.glsl)

Avec de petites modifications, je suppose que cela pourrait également fonctionner pour C.

Exaeta
la source
-1

dans xh

"this is a "
"buncha text"

dans main.c

#include <stdio.h>
int main(void)
{
    char *textFileContents =
#include "x.h"
    ;

    printf("%s\n", textFileContents);

    return 0
}

devrait faire le travail.

EvilTeach
la source
Pour plusieurs lignes, vous devez ajouter \ n donc: "ligne 1 \ n" "ligne 2 \ n"
Superfly Jon
c'est un peu trompeur, évidemment cela nécessite une certaine préparation du fichier texte pour ajouter des guillemets et \ n caractères, ne fonctionne pas dans le cas général
Mark Ch