"#include " plik tekstowy w programie C jako znak[]
Czy istnieje sposób na dołączenie całego pliku tekstowego jako ciągu znaków w programie C podczas kompilacji?
Coś w stylu:
-
Plik.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); }
Uzyskanie małego programu, który drukuje na stdout "to trochę plik tekstowy "
W tej chwili użyłem hackish python script, ale jest butt-brzydki i ograniczony tylko do jednej nazwy zmiennej, możesz mi powiedzieć inny sposób, aby to zrobić?
15 answers
Sugerowałbym użycie (unix util) xxd do tego celu. możesz go tak używać
$ echo hello world > a
$ xxd -i a
Wyjścia:
unsigned char a[] = {
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-04 13:56:22
Pytanie dotyczyło C, ale w przypadku, gdy ktoś spróbuje zrobić to z C++11, można to zrobić tylko z niewielkimi zmianami w dołączonym pliku tekstowym dzięki nowym surowym literałom łańcuchowym :
W C++ zrób to:
const char *s =
#include "test.txt"
;
W pliku tekstowym zrób tak:
R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"
Więc musi być tylko prefiks na górze pliku i sufiks na jego końcu. Pomiędzy nimi możesz robić, co chcesz, żadne specjalne ucieczki nie są konieczne, o ile nie potrzebujesz sekwencji znaków )"
. Ale nawet to może działać, jeśli podasz swój własny ogranicznik:
R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-07 18:14:34
Masz dwie możliwości:
- Użyj rozszerzeń kompilatora/linkera, aby przekonwertować plik do pliku binarnego, z odpowiednimi symbolami wskazującymi początek i koniec danych binarnych. Zobacz tę odpowiedź: Dołącz plik binarny za pomocą skryptu linkera GNU LD .
- Konwertuj plik do sekwencji stałych znaków, które mogą zainicjalizować tablicę. Uwaga nie można po prostu zrobić "" i rozciągnąć wiele linii. Potrzebujesz znaku kontynuacji linii (
\
), escape"
postaci i innych, aby to zadziałało. Łatwiej jest napisać mały program do konwersji bajtów na sekwencję podobną do'\xFF', '\xAB', ...., '\0'
(lub użyć narzędzia uniksowegoxxd
opisanego przez inną odpowiedź, jeśli masz ją dostępną!):
Kod:
#include <stdio.h>
int main() {
int c;
while((c = fgetc(stdin)) != EOF) {
printf("'\\x%X',", (unsigned)c);
}
printf("'\\0'"); // put terminating zero
}
(nie testowane). Więc zrób:
char my_file[] = {
#include "data.h"
};
Gdzie dane.H jest generowane przez
cat file.bin | ./bin2c > data.h
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03
OK, zainspirowany postem Daemin ' a przetestowałem następujący prosty przykład:
A. data:
"this is test\n file\n"
Test.c:
int main(void)
{
char *test =
#include "a.data"
;
return 0;
}
Test Gcc - E.wyjście 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;
}
Więc to działa, ale wymaga danych otoczonych cudzysłowami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32
Co może zadziałać, jeśli zrobisz coś takiego:
int main()
{
const char* text = "
#include "file.txt"
";
printf("%s", text);
return 0;
}
Oczywiście będziesz musiał uważać na to, co jest w pliku, upewniając się, że nie ma podwójnych cudzysłowów, że wszystkie odpowiednie znaki są unikalne itp.
Dlatego może być łatwiej, jeśli po prostu załadujesz tekst z pliku w czasie wykonywania lub osadzisz go bezpośrednio w kodzie.
Jeśli nadal chcesz tekst w innym pliku, możesz go tam mieć, ale musiałby być tam reprezentowany jako sznurek. Możesz użyć kodu jak powyżej, ale bez podwójnych cudzysłowów w nim. Na przykład:
"Something evil\n"\
"this way comes!"
int main()
{
const char* text =
#include "file.txt"
;
printf("%s", text);
return 0;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-04 22:15:22
Potrzebujesz mojego xtr
narzędzia, ale możesz to zrobić za pomocą bash script
. To jest skrypt, który nazywam bin2inc
. Pierwszym parametrem jest nazwa wynikowego char[] variable
. Drugim parametrem jest nazwa file
. Wyjście to C {[6] } z zawartością pliku zakodowaną (małymi literami hex
) jako podana nazwa zmiennej. char array
jest zero terminated
, a długość danych jest przechowywana w $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")';'
Możesz pobrać XTR tutaj xtr (ekstrapolator znaków) to GPLV3
Możesz to zrobić używając objcopy
:
objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o
Teraz masz plik obiektowy, który możesz połączyć z plikiem wykonywalnym, który zawiera symbole dla początku, końca i rozmiaru zawartości z myfile.txt
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-14 14:37:24
Podoba mi się odpowiedź kayahr. Jeśli jednak nie chcesz dotykać plików wejściowych , a jeśli używasz CMake , możesz dodać sekwencje znaków delimetra do pliku. Na przykład następujący kod CMake kopiuje pliki wejściowe i odpowiednio zawija ich zawartość:
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)
Następnie dołącz w c++ Tak:
constexpr char *test =
#include "generated/cool.frag"
;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-13 23:23:47
I reimplemented xxd in python3, fixing all of xxd ' s annoyances:
- Constitution
- string length datatype: int → size_t
- null termination (In case you might want that)
- C string compatible: Drop
unsigned
na tablicy. - Mniejsze, czytelne Wyjście, tak jak byś to napisał: Printable ascii jest wyjściem as-is; inne bajty są zakodowane szesnastkowo.
Oto skrypt, przefiltrowany przez siebie, więc możesz zobaczyć, co to czy:
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;
Użycie (to wyciąga skrypt):
#include <stdio.h>
extern const char pyxxd[];
extern const size_t pyxxd_len;
int main()
{
fwrite(pyxxd, 1, pyxxd_len, stdout);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-27 11:29:51
Nawet jeśli można to zrobić w czasie kompilacji (nie sądzę, że w ogóle), tekst prawdopodobnie będzie wstępnie przetworzonym nagłówkiem, a nie zawartością plików dosłownie. Spodziewam się, że będziesz musiał załadować tekst z pliku w czasie wykonywania lub wykonać paskudne zadanie cut-n-paste.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-04 13:54:40
W x.h
"this is a "
"buncha text"
In main.c
#include <stdio.h>
int main(void)
{
char *textFileContents =
#include "x.h"
;
printf("%s\n", textFileContents);
return 0
}
/ Align = "left" /Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-04 21:58:26
Odpowiedź Hasturkuna za pomocą opcji xxd-i jest doskonała. Jeśli chcesz włączyć proces konwersji (tekst - > hex Dołącz plik) bezpośrednio do kompilacji zrzutu heksowego.narzędzie / biblioteka c ostatnio dodała możliwość podobną do opcji xxd-i (nie daje pełnego nagłówka-musisz podać definicję tablicy znaków - ale to ma tę zaletę, że pozwala wybrać nazwę znaku array):
Http://25thandclement.com / ~william/projects/hexdump.c.html
Jego licencja jest o wiele bardziej "standardowa" niż xxd i jest bardzo liberalna - przykład użycia jej do osadzenia pliku init w programie można zobaczyć w Cmakelistach.txt i scheme.pliki c Tutaj:
Https://github.com/starseeker/tinyscheme-cmake
Istnieją plusy i minusy zarówno w tym generowanych plików w drzewach źródłowych, jak i wiązania narzędzi-jak sobie z tym poradzić będzie zależeć od konkretne cele i potrzeby Twojego projektu. zrzut heksowy.c otwiera opcję wiązania dla tej aplikacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-14 04:20:10
Myślę, że nie jest to możliwe tylko z kompilatorem i preprocesorem. gcc pozwala na to:
#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" );
Ale niestety nie to:
#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)
printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
STRGF(
# include "/etc/hostname"
)
"\n" );
Błąd to:
/etc/hostname: In function ‘init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-15 13:59:29
Dlaczego nie połączyć tekstu z programem i użyć go jako zmiennej globalnej! Oto przykład. rozważam użycie tego do włączenia otwartych plików GL shader w pliku wykonywalnym, ponieważ shadery GL muszą być skompilowane dla GPU w czasie wykonywania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-11 05:24:18
Miałem podobne problemy, a w przypadku małych plików wspomniane rozwiązanie Johannesa Schauba działało jak urok dla mnie.
Jednak w przypadku plików, które są nieco większe, napotkano problemy z limitem tablicy znaków kompilatora. Dlatego napisałem małą aplikację kodującą, która konwertuje zawartość pliku do tablicy znaków 2D o jednakowych rozmiarach (i ewentualnie Zerach wypełniających). Generuje wyjściowe pliki tekstowe z danymi tablicy 2D w następujący sposób:
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'}};
Gdzie 4 jest w rzeczywistości zmienna MAX_CHARS_PER_ARRAY w koderze. Plik z wynikowym kodem C, nazywany na przykład " main_js_file_data.h " może być następnie łatwo zaimplementowany w aplikacji C++, na przykład w następujący sposób:
#include "main_js_file_data.h"
Oto kod źródłowy kodera:
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-31 00:03:01