Gibt es eine Möglichkeit, eine ganze Textdatei zur Kompilierungszeit als Zeichenfolge in ein C-Programm aufzunehmen?
etwas wie:
file.txt:
This is a little text file
Haupt c:
#include <stdio.h> int main(void) { #blackmagicinclude("file.txt", content) /* equiv: char[] content = "This is\na little\ntext file"; */ printf("%s", content); }
ein kleines Programm erhalten, das auf stdout druckt "Dies ist eine kleine Textdatei"
Im Moment habe ich ein hackiges Python-Skript verwendet, aber es ist hässlich und auf nur einen Variablennamen beschränkt. Können Sie mir einen anderen Weg nennen, dies zu tun?
c
include
c-preprocessor
Brian Tompsett - 汤 莱恩
quelle
quelle
Antworten:
Ich würde vorschlagen, dafür (unix util) xxd zu verwenden. Sie können es so verwenden
Ausgänge:
quelle
xxd
, wie die Antwort sagt. Der Name des Arrays ist der Eingabedateiname. Wenn Sie Daten einleiten, anstatt eine Eingabedatei zu verwenden, erhalten Sie stattdessen eine Liste mit hexadezimalen Werten (ohne die Array-Deklaration oder die Variable len).xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
Die Frage betraf C, aber falls jemand versucht, dies mit C ++ 11 zu tun, kann dies dank der neuen rohen String-Literale mit nur geringen Änderungen an der enthaltenen Textdatei geschehen :
Führen Sie in C ++ Folgendes aus:
Führen Sie in der Textdatei Folgendes aus:
Es darf also nur ein Präfix am Anfang der Datei und ein Suffix am Ende der Datei stehen. Dazwischen können Sie tun, was Sie wollen, es ist kein spezielles Escape erforderlich, solange Sie die Zeichenfolge nicht benötigen
)"
. Aber auch dies kann funktionieren, wenn Sie Ihr eigenes benutzerdefiniertes Trennzeichen angeben:quelle
1+R"...
stattdessenR"...
als Starttrennzeichen verwenden und dann vorher eine neue Zeile voranstellenLine 1
. Dadurch wird der Ausdruck von einem Array in einen Zeiger umgewandelt. Dies ist hier jedoch kein wirkliches Problem, da Sie einen Zeiger und kein Array initialisieren.Sie haben zwei Möglichkeiten:
\
), Escapezeichen"
und andere, damit dies funktioniert. Einfacher, ein kleines Programm zu schreiben, um die Bytes in eine Sequenz wie zu konvertieren'\xFF', '\xAB', ...., '\0'
(oder dasxxd
durch eine andere Antwort beschriebene Unix-Tool zu verwenden , falls verfügbar)!Code:
(nicht getestet). Dann mach:
Wobei data.h von generiert wird
quelle
char my_file[] = { #include my_large_file.h };
Thanks!bin2c
ist nicht das gleiche bin2c wie von debianhxtools
, Vorsichtbin2c -H myoutput.h myinput1.txt myinputN.txt
ok, inspiriert von Daemins Beitrag habe ich folgendes einfaches Beispiel getestet:
a.data:
test.c:
gcc -E test.c Ausgabe:
Es funktioniert also, erfordert jedoch Daten in Anführungszeichen.
quelle
Ich mag Kayahrs Antwort. Wenn Sie die Eingabedateien jedoch nicht berühren möchten und CMake verwenden , können Sie der Datei die Begrenzungszeichenfolgen hinzufügen. Der folgende CMake-Code kopiert beispielsweise die Eingabedateien und verpackt ihren Inhalt entsprechend:
Fügen Sie dann in c ++ Folgendes ein:
quelle
Sie können dies tun mit
objcopy
:Jetzt haben Sie eine Objektdatei, die Sie mit Ihrer ausführbaren Datei verknüpfen können und die Symbole für den Anfang, das Ende und die Größe des Inhalts enthält
myfile.txt
.quelle
Du brauchst mein
xtr
Dienstprogramm, aber du kannst es mit einem machenbash script
. Dies ist ein Skript, das ich aufrufebin2inc
. Der erste Parameter ist der Name des Ergebnisseschar[] variable
. Der zweite Parameter ist der Name desfile
. Die Ausgabe ist C,include file
wobei der Dateiinhalt (in Kleinbuchstabenhex
) als Variablenname codiert ist . Daschar array
istzero terminated
und die Länge der Daten wird in gespeichert$variableName_length
SIE KÖNNEN HIER XTR ERHALTEN xtr (Zeichen eXTRapolator) ist GPLV3
quelle
Wenn Sie bereit sind, auf schmutzige Tricks zurückzugreifen, können Sie mit rohen String-Literalen und kreativ werden
#include
für bestimmte Dateitypen werden.Angenommen, ich möchte einige SQL-Skripte für SQLite in mein Projekt aufnehmen und möchte Syntaxhervorhebungen erhalten, möchte aber keine spezielle Build-Infrastruktur. Ich kann diese Datei haben,
test.sql
die SQL für SQLite ist, wo--
ein Kommentar beginnt:Und dann kann ich in meinem C ++ - Code Folgendes haben:
Die Ausgabe ist:
Oder um Python-Code aus einer Datei einzufügen,
test.py
die ein gültiges Python-Skript ist (weil#
ein Kommentar in Python startet undpass
ein No-Op ist):Und dann im C ++ - Code:
Welches wird ausgegeben:
Es sollte möglich sein, ähnliche Streiche für verschiedene andere Codetypen zu spielen, die Sie möglicherweise als Zeichenfolge einfügen möchten. Ob es eine gute Idee ist oder nicht, weiß ich nicht genau. Es ist eine Art ordentlicher Hack, aber wahrscheinlich nichts, was Sie in echtem Produktionscode wollen würden. Könnte aber für ein Wochenend-Hack-Projekt in Ordnung sein.
quelle
Ich habe xxd in python3 neu implementiert und alle Probleme von xxd behoben:
unsigned
Auf dem Array ablegen.Hier ist das Skript, das von selbst gefiltert wurde, damit Sie sehen können, was es tut:
pyxxd.c
Verwendung (dies extrahiert das Skript):
quelle
Was funktionieren könnte , ist, wenn Sie etwas tun wie:
Natürlich müssen Sie vorsichtig sein mit dem, was tatsächlich in der Datei enthalten ist , und sicherstellen, dass keine doppelten Anführungszeichen vorhanden sind, dass alle entsprechenden Zeichen maskiert sind usw.
Daher ist es möglicherweise einfacher, wenn Sie den Text zur Laufzeit nur aus einer Datei laden oder ihn direkt in den Code einbetten.
Wenn Sie den Text noch in einer anderen Datei haben möchten, könnten Sie ihn dort haben, aber er müsste dort als Zeichenfolge dargestellt werden. Sie würden den Code wie oben verwenden, jedoch ohne die doppelten Anführungszeichen. Beispielsweise:
file.txt
main.cpp
Im Grunde genommen haben Sie eine Zeichenfolge im C- oder C ++ - Stil in einer Textdatei, die Sie einschließen. Dies würde den Code übersichtlicher machen, da am Anfang der Datei nicht so viel Text vorhanden ist.
quelle
Selbst wenn dies zur Kompilierungszeit möglich ist (ich glaube nicht, dass dies im Allgemeinen möglich ist), wäre der Text wahrscheinlich eher der vorverarbeitete Header als der wörtliche Inhalt der Dateien. Ich gehe davon aus, dass Sie den Text zur Laufzeit aus der Datei laden oder einen fiesen Job zum Ausschneiden und Einfügen ausführen müssen.
quelle
Hasturkuns Antwort mit der Option xxd -i ist ausgezeichnet. Wenn Sie den Konvertierungsprozess (Text -> Hex-Include-Datei) direkt in Ihren Build integrieren möchten, hat das Tool / die Bibliothek hexdump.c kürzlich eine Funktion hinzugefügt, die der Option -i von xxd ähnelt (Sie erhalten nicht den vollständigen Header -, die Sie benötigen um die Definition des char-Arrays bereitzustellen - dies hat jedoch den Vorteil, dass Sie den Namen des char-Arrays auswählen können):
http://25thandclement.com/~william/projects/hexdump.c.html
Die Lizenz ist viel "Standard" als xxd und sehr liberal. Ein Beispiel für die Verwendung zum Einbetten einer Init-Datei in ein Programm finden Sie in den Dateien CMakeLists.txt und Schema.c hier:
https://github.com/starseeker/tinyscheme-cmake
Das Einfügen generierter Dateien in Quellbäume und das Bündeln von Dienstprogrammen hat Vor- und Nachteile. Wie Sie damit umgehen, hängt von den spezifischen Zielen und Anforderungen Ihres Projekts ab. hexdump.c öffnet die Bündelungsoption für diese Anwendung.
quelle
Ich denke, dass es mit dem Compiler und Präprozessor allein nicht möglich ist. gcc erlaubt dies:
Aber leider nicht das:
Der Fehler ist:
quelle
/etc/hostname
eine Möglichkeit, den Namen der Build-Maschine in die Zeichenfolge einzubetten, was (selbst wenn es funktionieren würde) nicht wäre portabel, da Mac OS X keine Datei hat/etc/hostname
. Beachten Sie, dass bei der Verwendung von Makronamen, die mit einem Unterstrich gefolgt von einem Großbuchstaben beginnen, ein für die Implementierung reservierter Name verwendet wird, nämlich A Bad Thing ™.Verknüpfen Sie den Text mit dem Programm und verwenden Sie ihn als globale Variable. Hier ist ein Beispiel. Ich denke darüber nach, Open GL-Shader-Dateien in eine ausführbare Datei aufzunehmen, da GL-Shader zur Laufzeit für die GPU kompiliert werden müssen.
quelle
Ich hatte ähnliche Probleme, und für kleine Dateien wirkte die oben erwähnte Lösung von Johannes Schaub wie ein Zauber für mich.
Bei etwas größeren Dateien traten jedoch Probleme mit dem Zeichenarray-Limit des Compilers auf. Aus diesem Grund habe ich eine kleine Encoder-Anwendung geschrieben, die Dateiinhalte in ein 2D-Zeichenarray mit gleich großen Blöcken (und möglicherweise aufgefüllten Nullen) konvertiert. Es werden Ausgabetextdateien mit 2D-Array-Daten wie folgt erstellt:
Dabei ist 4 tatsächlich eine Variable MAX_CHARS_PER_ARRAY im Encoder. Die Datei mit dem resultierenden C-Code, beispielsweise "main_js_file_data.h", kann dann einfach in die C ++ - Anwendung eingefügt werden, beispielsweise wie folgt:
Hier ist der Quellcode des Encoders:
quelle
Dieses Problem hat mich irritiert und xxd funktioniert für meinen Anwendungsfall nicht, da die Variable __home_myname_build_prog_cmakelists_src_autogen beim Versuch, ein Skript zu erstellen, erstellt wurde. Daher habe ich ein Dienstprogramm erstellt, um genau dieses Problem zu lösen:
https://github.com/Exaeta/brcc
Es generiert eine Quell- und Header-Datei und ermöglicht es Ihnen, den Namen jeder Variablen explizit festzulegen, damit Sie sie über std :: begin (arrayname) und std :: end (arrayname) verwenden können.
Ich habe es wie folgt in mein cmake-Projekt aufgenommen:
Mit kleinen Änderungen könnte es auch für C funktionieren.
quelle
in xh
in main.c
sollte den Job machen.
quelle