Một số tập tin văn bản trong chương trình C dưới dạng char []


130

Có cách nào để bao gồm toàn bộ tệp văn bản dưới dạng chuỗi trong chương trình C tại thời gian biên dịch không?

cái gì đó như:

  • file.txt:

    This is
    a little
    text file
  • C chính:

    #include <stdio.h>
    int main(void) {
       #blackmagicinclude("file.txt", content)
       /*
       equiv: char[] content = "This is\na little\ntext file";
       */
       printf("%s", content);
    }

có được một chương trình nhỏ in trên thiết bị xuất chuẩn "Đây là một tệp văn bản nhỏ"

Hiện tại tôi đã sử dụng một kịch bản python hackish, nhưng nó xấu xí và chỉ giới hạn ở một tên biến, bạn có thể cho tôi biết một cách khác để làm điều đó không?


Hãy xem ở đây để đọc một tập tin vào một char []. /programming/410943/reading-a-text-file-into-an-array-in-c Dưới đây là một số mẹo sử dụng macro của bộ tiền xử lý C. http://gcc.gnu.org/onlinesocs/cpp/Macros.html
Daniel A. White

3
tại sao bạn muốn làm việc này? Tại sao không đọc các tập tin trong thời gian chạy? (Trả lời: có thể vì khó biết tệp đang ở đâu trong thời gian chạy hoặc có thể vì chỉ nên có một tệp để cài đặt.)
Jonathan Leffler

hoặc, có thể tệp văn bản chỉ khả dụng tại thời điểm biên dịch, chẳng hạn như mã nguồn.
TMS

1
Đôi khi bạn muốn truy cập dữ liệu dưới dạng các tệp riêng biệt tại thời điểm phát triển nhưng có nội dung được biên dịch thành tệp nhị phân của bạn. Ví dụ đang chạy một máy chủ web trên Arduino mà không có quyền truy cập vào bộ nhớ cục bộ. Bạn muốn tách riêng các tệp html của mình để chỉnh sửa chúng nhưng tại thời điểm biên dịch chúng cần tồn tại dưới dạng chuỗi trong nguồn của bạn.
Geordie

Câu trả lời:


134

Tôi khuyên bạn nên sử dụng (unix produc) xxd cho việc này. bạn có thể sử dụng nó như vậy

$ echo hello world > a
$ xxd -i a

đầu ra:

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

18
Chỉ cần một lưu ý: char [] được tạo bởi xxd không bị chấm dứt NULL! vì vậy tôi làm $ xxd -i <file.txt> file.xxd $ echo ', 0' >> file.xxd và trong tệp main.c char file_content [] = {#include "file.xxd"};

2
Tôi chưa bao giờ biết về xxd. Thật tuyệt vời!

1
@eSKay: điều đó xuất phát trực tiếp từ đầu ra của xxd, như câu trả lời nói. Tên của mảng là tên tệp đầu vào. nếu bạn đang truyền dữ liệu thay vì sử dụng tệp đầu vào, bạn sẽ nhận được một danh sách các giá trị thập lục phân thay thế (không có khai báo mảng hoặc biến len).
Hasturkun

4
Điều đó cực kỳ hữu ích khi nhúng các shader GLSL.
linello

5
Một cách khác để thêm chấm dứt 0x00 vào xxd được tạo mã C:xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
vleo

104

Câu hỏi là về C nhưng trong trường hợp ai đó cố gắng thực hiện với C ++ 11 thì có thể thực hiện chỉ với một vài thay đổi đối với tệp văn bản được bao gồm nhờ vào chuỗi ký tự thô mới :

Trong C ++, hãy làm điều này:

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

Trong tệp văn bản làm điều này:

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

Vì vậy, chỉ phải có một tiền tố ở đầu tệp và hậu tố ở cuối tệp. Giữa nó bạn có thể làm những gì bạn muốn, không cần thoát đặc biệt miễn là bạn không cần chuỗi ký tự )". Nhưng ngay cả điều này có thể hoạt động nếu bạn chỉ định dấu phân cách tùy chỉnh của riêng bạn:

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

5
Cảm ơn, tôi đã chọn phương pháp được đề xuất ở đây để nhúng các đoạn sql dài vào mã C ++ 11 của tôi. Điều này cho phép tôi giữ SQL tách biệt thành các tệp riêng và chỉnh sửa chúng bằng cách kiểm tra cú pháp, tô sáng thích hợp, v.v.
YitzikC

1
Điều này thực sự gần với những gì tôi muốn. Đặc biệt là người sử dụng xác định dấu phân cách. Rất hữu ích. Tôi muốn tiến thêm một bước: có cách nào để loại bỏ hoàn toàn tiền tố R "(và hậu tố)" khỏi tệp bạn muốn đưa vào không? Tôi đã thử với định nghĩa hai tệp được gọi là bra.in và ket.in với tiền tố và hậu tố trong đó, bao gồm bra.in, file.txt và ket.in từng cái một. Nhưng trình biên dịch đánh giá nội dung của bra.in (chỉ là R "() trước khi bao gồm tệp tiếp theo. Vì vậy, nó sẽ khiếu nại. Vui lòng cho tôi biết nếu có ai biết cách sử dụng tiền tố và hậu tố từ file.txt. Cảm ơn.
TMS

Tôi đoán C ++ sẽ không cho phép R "(<newline> #include ...)"? Sẽ rất tuyệt nếu tệp được biên dịch theo thời gian để không yêu cầu bất kỳ mã hóa nào .... tức là json thẳng hoặc xml hoặc csv hoặc những gì không ..
Brian Chrisman

Bạn có thể làm cho văn bản của chữ thô dễ đọc hơn một chút nếu bạn sử dụng 1+R"...làm dấu phân cách bắt đầu thay vì R"..., sau đó đăng ký một dòng mới trước đó Line 1. Điều này sẽ biến đổi biểu thức từ một mảng thành một con trỏ, nhưng đó không thực sự là vấn đề ở đây, vì bạn đang khởi tạo một con trỏ, không phải là một mảng.
Ruslan

14

Bạn có hai khả năng:

  1. Sử dụng các phần mở rộng trình biên dịch / liên kết để chuyển đổi một tệp thành một tệp nhị phân, với các ký hiệu thích hợp chỉ đến điểm bắt đầu và kết thúc của dữ liệu nhị phân. Xem câu trả lời này: Bao gồm tệp nhị phân với tập lệnh liên kết GNU ld .
  2. Chuyển đổi tệp của bạn thành một chuỗi các hằng ký tự có thể khởi tạo một mảng. Lưu ý bạn không thể chỉ làm "" và kéo dài nhiều dòng. Bạn sẽ cần một ký tự tiếp tục dòng ( \), thoát các "ký tự và các ký tự khác để làm cho công việc đó. Dễ dàng hơn chỉ cần viết một chương trình nhỏ để chuyển đổi các byte thành một chuỗi như '\xFF', '\xAB', ...., '\0'(hoặc sử dụng công cụ unix xxdđược mô tả bởi một câu trả lời khác, nếu bạn có sẵn nó!):

Mã số:

#include <stdio.h>

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

(không được kiểm tra). Sau đó làm:

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

Nơi data.h được tạo bởi

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

1
dòng cuối cùng có lẽ nên đọc "cat file.bin | ./bin2c> data.h" hoặc "./bin2c <file.bin> data.h"
Hasturkun

Tôi đã sử dụng codeproject.com/Tips/845393/ trên để tạo một tệp hex (trên Windows) từ tệp nhị phân và sau đó sử dụng đề xuất của bạn về char my_file[] = { #include my_large_file.h };Cảm ơn!
Ai đó ở đâu đó

bin2ckhông những bin2c giống như từ của debian hxtools, hãy cẩn thận
ThorSummoner

hoặc nếu có, lời mời bây giờ kỳ lạ hơn nhiều:bin2c -H myoutput.h myinput1.txt myinputN.txt
ThorSummoner

9

ok, lấy cảm hứng từ bài đăng của Daemin tôi đã thử nghiệm ví dụ đơn giản sau:

a.data:

"this is test\n file\n"

kiểm tra

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

gcc -E test.c đầu ra:

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

Vì vậy, nó hoạt động nhưng yêu cầu dữ liệu được bao quanh với dấu ngoặc kép.


Đó là những gì tôi đã ám chỉ trong phần cuối của câu trả lời của tôi.
Daemin

trích dẫn, hoặc bất cứ điều gì nó được gọi, xin lỗi tiếng Anh của tôi
Ilya

Điều này đòi hỏi dữ liệu phải được thoát C. Tôi không nghĩ đó là những gì bài viết đang tìm kiếm. Nếu điều này có một số loại macro bao gồm mà C đã thoát khỏi nội dung của tệp, điều đó sẽ ổn.
Brian Chrisman

8

Tôi thích câu trả lời của kayahr. Tuy nhiên, nếu bạn không muốn chạm vào các tệp đầu vào và nếu bạn đang sử dụng CMake , bạn có thể thêm các chuỗi ký tự phân cách trên tệp. Ví dụ, mã CMake sau đây sao chép các tệp đầu vào và bao bọc nội dung của chúng tương ứng:

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)

Sau đó, bao gồm trong c ++ như thế này:

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

5

Bạn có thể làm điều này bằng cách sử dụng objcopy:

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

Bây giờ bạn có một tệp đối tượng, bạn có thể liên kết vào tệp thực thi của mình có chứa các ký hiệu cho phần đầu, phần cuối và kích thước của nội dung từ myfile.txt .


1
bạn có thể cho chúng tôi biết tên biểu tượng sẽ là gì không?
Đánh dấu

@MarkCh: Theo tài liệu, tên biểu tượng được tạo từ tên tệp đầu vào.
John Zwinck

Tôi đoán điều này sẽ không hoạt động trên các máy không x86-64, phải không?
ThorSummoner


2

Bạn cần xtrtiện ích của tôi nhưng bạn có thể làm điều đó với a bash script. Đây là một kịch bản tôi gọi bin2inc. Tham số đầu tiên là tên của kết quả char[] variable. Tham số thứ hai là tên của file. Đầu ra là C include filevới nội dung tệp được mã hóa (bằng chữ thường hex) là tên biến đã cho. Các char arrayzero terminated, và chiều dài của dữ liệu được lưu trữ trong$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")';'

BẠN CÓ THỂ NHẬN XTR TẠI ĐÂY xtr (ký tự eXTRapolator) là GPLV3


2

Nếu bạn sẵn sàng sử dụng một số thủ thuật bẩn, bạn có thể sáng tạo với chuỗi ký tự thô và #includecho một số loại tệp nhất định.

Ví dụ: giả sử tôi muốn đưa một số tập lệnh SQL cho SQLite vào dự án của mình và tôi muốn làm nổi bật cú pháp nhưng không muốn bất kỳ cơ sở hạ tầng xây dựng đặc biệt nào. Tôi có thể có tệp test.sqlnày là SQL hợp lệ cho SQLite khi --bắt đầu nhận xét:

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

Và sau đó trong mã C ++ của tôi, tôi có thể có:

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

    cout << mysql << endl;
}

Đầu ra là:

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

Hoặc để bao gồm một số mã Python từ một tệp test.pylà tập lệnh Python hợp lệ (vì #bắt đầu nhận xét bằng Python và passkhông có mã nguồn):

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

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

Và sau đó trong mã C ++:

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

    cout << mypython << endl;
}

Sẽ xuất ra:

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

myfunc()
#undef pass
#define pass

Có thể chơi các thủ thuật tương tự đối với các loại mã khác nhau mà bạn có thể muốn đưa vào dưới dạng chuỗi. Có hay không đó là một ý tưởng tốt, tôi không chắc chắn. Đó là một bản hack gọn gàng nhưng có lẽ không phải là thứ bạn muốn trong mã sản xuất thực. Có thể là ok cho một dự án hack cuối tuần mặc dù.


Tôi cũng đã sử dụng phương pháp này để đưa OpenGL Shader vào các tệp văn bản!
yano

1

Tôi đã thực hiện lại xxd trong python3, khắc phục tất cả các phiền toái của xxd:

  • Const đúng
  • kiểu dữ liệu độ dài chuỗi: int → size_t
  • Chấm dứt không (trong trường hợp bạn có thể muốn điều đó)
  • Tương thích chuỗi C: Thả unsignedtrên mảng.
  • Đầu ra nhỏ hơn, dễ đọc hơn, như bạn đã viết: Ascii có thể in là đầu ra nguyên trạng; các byte khác được mã hóa hex.

Đây là kịch bản, được lọc bởi chính nó, vì vậy bạn có thể thấy những gì nó làm:

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;

Cách sử dụng (phần này trích xuất tập lệnh):

#include <stdio.h>

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

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

1

Những gì có thể làm việc là nếu bạn làm một cái gì đó như:

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

Tất nhiên bạn sẽ phải cẩn thận với những gì thực sự có trong tập tin , đảm bảo không có dấu ngoặc kép, tất cả các ký tự phù hợp đều được thoát, v.v.

Do đó, có thể dễ dàng hơn nếu bạn chỉ tải văn bản từ một tệp trong thời gian chạy hoặc nhúng văn bản trực tiếp vào mã.

Nếu bạn vẫn muốn văn bản trong một tệp khác, bạn có thể có nó trong đó, nhưng nó sẽ phải được thể hiện ở đó dưới dạng một chuỗi. Bạn sẽ sử dụng mã như trên nhưng không có dấu ngoặc kép trong đó. Ví dụ:

file.txt

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

main.cpp

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

Vì vậy, về cơ bản có một chuỗi kiểu C hoặc C ++ trong một tệp văn bản mà bạn đưa vào. Nó sẽ làm cho mã gọn gàng hơn vì không có nhiều văn bản khổng lồ này khi bắt đầu tập tin.


3
Ý tưởng hay nhưng nó sẽ không hoạt động, hoặc bạn có lỗi vì nghĩa đen bao gồm một dòng mới hoặc phần #incoide sẽ được đọc dưới dạng một chuỗi và không được thực thi, bị nguyền rủa nếu bạn làm và bị nguyền rủa nếu bạn không .. .
Motti

1
@Motti: đã đồng ý - như đã viết, không hợp lệ về mặt cú pháp C. Ý tưởng rất thú vị - Bộ xử lý trước C là một giai đoạn riêng biệt - nhưng thực tế là nó không khởi đầu được vì mỗi dòng trong tệp được bao gồm sẽ có kết thúc bằng dấu gạch chéo ngược, v.v.
Jonathan Leffler

2
Hừm. Dường như với tôi rằng bạn không cần dấu gạch chéo ngược vì hầu hết các trình biên dịch sẽ nối các chuỗi liên kết với nhau
EvilTeach

Điều với câu trả lời này là ... nếu nó đơn giản, tôi không nghĩ OP sẽ đặt câu hỏi! -1 vì sự hiện diện của câu trả lời này hơi khuyến khích mọi người lãng phí thời gian để thử thứ gì đó không hiệu quả. Tôi nghĩ rằng chúng tôi có thể xóa downvote nếu bạn thay đổi "Điều gì có thể hoạt động" thành "Để tham khảo, điều này không hoạt động"
Mark Ch

@JonathanLeffler Sau khi bộ tiền xử lý chạy, nó phải là C hoặc C ++ hợp lệ tùy thuộc vào cách định dạng file.txt.
Daemin

0

Ngay cả khi nó có thể được thực hiện vào thời gian biên dịch (tôi không nghĩ nó có thể nói chung), văn bản có thể sẽ là tiêu đề được xử lý trước chứ không phải là nội dung tệp nguyên văn. Tôi hy vọng bạn sẽ phải tải văn bản từ tệp trong thời gian chạy hoặc thực hiện một công việc cắt dán khó chịu.


0

Câu trả lời của Hasturkun sử dụng tùy chọn xxd -i là tuyệt vời. Nếu bạn muốn kết hợp trực tiếp quá trình chuyển đổi (văn bản -> tệp bao gồm hex) vào công cụ / thư viện hexdump.c của bạn gần đây đã thêm một khả năng tương tự như tùy chọn -x của xxd (nó không cung cấp cho bạn tiêu đề đầy đủ - bạn cần để cung cấp định nghĩa mảng char - nhưng điều đó có lợi thế là cho phép bạn chọn tên của mảng char):

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

Giấy phép của nó "chuẩn" hơn rất nhiều so với xxd và rất tự do - một ví dụ về việc sử dụng nó để nhúng tệp init trong chương trình có thể được nhìn thấy trong các tệp CMakeLists.txt và sch.c ở đây:

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

Có cả ưu và nhược điểm để bao gồm các tệp được tạo trong cây nguồn và các tiện ích đi kèm - cách xử lý nó sẽ phụ thuộc vào các mục tiêu và nhu cầu cụ thể của dự án của bạn. hexdump.c mở ra tùy chọn gói cho ứng dụng này.


0

Tôi nghĩ rằng không thể chỉ với trình biên dịch và tiền xử lý. gcc cho phép điều này:

#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" );

Nhưng tiếc là không phải cái này:

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

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

Lỗi là:

/etc/hostname: In function init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"

Tôi đã nhìn, khi bạn trả giá cho tôi nhìn. Tôi không thấy bất kỳ thông tin mới nào trong câu trả lời của bạn (thông tin không có trong các câu trả lời khác), ngoài tham chiếu đến /etc/hostnamenhư là cách nhúng tên của máy xây dựng trong chuỗi, mà (ngay cả khi nó hoạt động) sẽ không xách tay vì Mac OS X không có tệp /etc/hostname. Lưu ý rằng việc sử dụng tên macro bắt đầu bằng dấu gạch dưới theo sau là chữ in hoa đang sử dụng tên dành riêng cho việc triển khai, đó là A Bad Thing ™.
Jonathan Leffler

0

Tại sao không liên kết văn bản vào chương trình và sử dụng nó như một biến toàn cục! Đây là một ví dụ. Tôi đang xem xét sử dụng điều này để bao gồm các tệp shader Open GL trong một tệp thực thi vì các shader GL cần được biên dịch cho GPU khi chạy.


0

Tôi đã có những vấn đề tương tự, và đối với các tập tin nhỏ, giải pháp đã nói ở trên của Julian Schaub hoạt động như một cơ duyên đối với tôi.

Tuy nhiên, đối với các tệp lớn hơn một chút, nó gặp vấn đề với giới hạn mảng ký tự của trình biên dịch. Do đó, tôi đã viết một ứng dụng mã hóa nhỏ để chuyển đổi nội dung tệp thành một mảng ký tự 2D gồm các đoạn có kích thước bằng nhau (và có thể là các số 0 đệm). Nó tạo ra các tệp văn bản đầu ra với dữ liệu mảng 2D như thế này:

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

trong đó 4 thực sự là một biến MAX_CHARS_PER_ARRAY trong bộ mã hóa. Tệp có mã C kết quả, được gọi, ví dụ "main_js_file_data.h" sau đó có thể dễ dàng được đưa vào ứng dụng C ++, ví dụ như sau:

#include "main_js_file_data.h"

Đây là mã nguồn của bộ mã hóa:

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

0

Vấn đề này đã gây khó chịu cho tôi và xxd không hoạt động cho trường hợp sử dụng của tôi vì nó đã tạo ra biến có tên là __home_myname_build_prog_cmakelists_src_autogen khi tôi cố gắng xử lý sự cố này, vì vậy tôi đã tạo một tiện ích để giải quyết vấn đề chính xác này:

https://github.com/Exaeta/brcc

Nó tạo ra một tệp nguồn và tiêu đề và cho phép bạn đặt tên của từng biến một cách rõ ràng để sau đó bạn có thể sử dụng chúng thông qua std :: started (tên mảng) và std :: end (tên mảng).

Tôi đã kết hợp nó vào dự án cmake của mình như vậy:

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)

Với những điều chỉnh nhỏ, tôi cho rằng nó cũng có thể được tạo ra để hoạt động cho C.


-1

trong xh

"this is a "
"buncha text"

trong main.c

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

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

    return 0
}

nên làm công việc


Đối với nhiều dòng, bạn cần thêm \ n vì vậy: "dòng 1 \ n" "dòng 2 \ n"
Superfly Jon

nó hơi sai lệch, rõ ràng điều này đòi hỏi một số chuẩn bị của tệp văn bản để thêm dấu ngoặc kép và \ n ký tự, không hoạt động trong trường hợp chung
Mark Ch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.