“ #include” ไฟล์ข้อความในโปรแกรม C เป็นอักขระ []


130

มีวิธีการรวมไฟล์ข้อความทั้งหมดเป็นสตริงในโปรแกรม C ที่รวบรวมเวลาหรือไม่

สิ่งที่ต้องการ:

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

การรับโปรแกรมเล็ก ๆ ที่พิมพ์บน stdout "นี่คือไฟล์ข้อความเล็ก ๆ "

ตอนนี้ฉันใช้สคริปต์ python ที่แฮ็ค แต่มันน่าเกลียดและ จำกัด ชื่อตัวแปรเพียงชื่อเดียวคุณช่วยบอกวิธีอื่นให้ฉันได้ไหม


ลองดูที่นี่เพื่ออ่านไฟล์เป็นตัวอักษร [] /programming/410943/reading-a-text-file-into-an-array-in-cนี่คือเคล็ดลับบางประการสำหรับการใช้มาโครของ C preprocessor http://gcc.gnu.org/onlinedocs/cpp/Macros.html
Daniel A. White

3
ทำไมคุณถึงต้องการทำเช่นนี้? ทำไมไม่อ่านไฟล์ตอนรันไทม์? (คำตอบ: อาจจะเพราะมันเป็นเรื่องยากที่จะทราบว่าไฟล์เป็นที่รันไทม์หรืออาจจะเพราะมีควรจะเป็นหนึ่งในการติดตั้งไฟล์.)
โจนาธาน Leffler

หรือไฟล์ข้อความอาจมีให้เฉพาะในเวลารวบรวมเช่นซอร์สโค้ด
TMS

1
บางครั้งคุณต้องการเข้าถึงข้อมูลเป็นไฟล์แยกต่างหากในเวลาพัฒนา แต่มีเนื้อหาที่รวบรวมไว้ในไบนารีของคุณ ตัวอย่างกำลังเรียกใช้เว็บเซิร์ฟเวอร์บน Arduino ซึ่งไม่สามารถเข้าถึงที่จัดเก็บในตัวเครื่อง คุณต้องการแยกไฟล์ html ของคุณออกเพื่อแก้ไข แต่ในเวลาคอมไพล์พวกเขาจำเป็นต้องมีอยู่เป็นสตริงในแหล่งที่มาของคุณ
Geordie

คำตอบ:


134

ฉันขอแนะนำให้ใช้ (unix util) xxdสำหรับสิ่งนี้ คุณสามารถใช้มันได้

$ echo hello world > a
$ xxd -i a

เอาท์พุท:

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

18
เพียงแค่ทราบ: ถ่าน [] สร้างโดย xxd ไม่ได้เป็นโมฆะ! ดังนั้นฉันจึงทำ $ xxd -i <file.txt> file.xxd $ echo ', 0' >> file.xxd และใน main.c char file_content [] = {#include "file.xxd"};

2
ฉันไม่เคยรู้เกี่ยวกับ xxd มันเจ๋งมาก!

1
@eSKay: ที่มาโดยตรงจากผลลัพธ์xxdเป็นคำตอบว่า ชื่อของอาร์เรย์คือชื่อไฟล์อินพุต หากคุณกำลังไพพ์ข้อมูลแทนที่จะใช้ไฟล์อินพุตคุณจะได้รับรายการค่าเลขฐานสิบหกแทน (โดยไม่มีการประกาศอาร์เรย์หรือตัวแปร len)
Hasturkun

4
มีประโยชน์อย่างยิ่งเมื่อฝัง GLSL shaders
linello

5
วิธีที่จะเพิ่ม 0x00 เลิก xxd อีกผลิตรหัส C:xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h
vleo

104

คำถามคือเกี่ยวกับ C แต่ในกรณีที่มีคนพยายามทำด้วย C ++ 11 ก็สามารถทำได้โดยการเปลี่ยนแปลงเพียงเล็กน้อยในไฟล์ข้อความที่รวมขอบคุณตัวอักษรสตริงสตริงใหม่:

ใน C ++ ให้ทำสิ่งนี้:

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

ในไฟล์ข้อความให้ทำสิ่งนี้:

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

ดังนั้นจะต้องมีคำนำหน้าที่ด้านบนของไฟล์และคำต่อท้ายที่ท้ายสุดเท่านั้น )"ระหว่างที่คุณสามารถทำสิ่งที่คุณต้องการพิเศษหลุดออกมาเป็นสิ่งที่จำเป็นตราบใดที่คุณไม่จำเป็นต้องลำดับตัวอักษร แต่สิ่งนี้สามารถใช้งานได้หากคุณระบุตัวคั่นที่กำหนดเองของคุณ:

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

5
ขอบคุณฉันเลือกวิธีที่เสนอที่นี่เพื่อฝังส่วนยาวของsqlลงในรหัส C ++ 11 ของฉัน สิ่งนี้ช่วยให้ฉันสามารถแยก SQL อย่างชัดเจนเป็นไฟล์ของตัวเองและแก้ไขด้วยการตรวจสอบไวยากรณ์ที่เหมาะสมการไฮไลต์ ฯลฯ
YitzikC

1
ใกล้กับสิ่งที่ฉันต้องการจริงๆ โดยเฉพาะอย่างยิ่งผู้ใช้กำหนดตัวคั่น มีประโยชน์มาก. ฉันต้องการไปอีกขั้น: มีวิธีลบคำนำหน้า R "(และคำต่อท้าย)" จากไฟล์ที่คุณต้องการรวมหรือไม่? ฉันพยายามกำหนดสองไฟล์ชื่อ bra.in และ ket.in ด้วยส่วนนำหน้าและส่วนต่อท้ายในนั้นรวม bra.in, file.txt และ ket.in ทีละไฟล์ แต่คอมไพเลอร์ประเมินเนื้อหาของ bra.in (ซึ่งเป็นเพียง R "() ก่อนรวมไฟล์ถัดไปดังนั้นมันจะบ่นโปรดแจ้งให้เราทราบหากใครรู้วิธีรับคำนำหน้าและคำต่อท้ายจาก file.txt ขอบคุณ
TMS

ฉันเดาว่า C ++ จะไม่อนุญาตให้ R "(<newline> #include ... )"? จะดีที่มีไฟล์ที่รวบรวมเวลาที่ติดเครื่องไม่จำเป็นต้องมีการเข้ารหัสใด ๆ .... เช่นตรง json หรือ xml หรือ csv หรือสิ่งที่ไม่ ..
Brian Chrisman

คุณสามารถทำให้ข้อความของตัวอักษรดิบบิตอ่านได้มากขึ้นถ้าคุณใช้1+R"...เป็นตัวคั่นเริ่มต้นแทนแล้วย่อหน้าขึ้นบรรทัดใหม่ก่อนR"... Line 1สิ่งนี้จะแปลงนิพจน์จากอาร์เรย์เป็นตัวชี้ แต่นั่นไม่ใช่ปัญหาจริงๆที่นี่เนื่องจากคุณกำลังเริ่มต้นตัวชี้ไม่ใช่อาร์เรย์
Ruslan

14

คุณมีความเป็นไปได้สองอย่าง:

  1. ใช้ประโยชน์จากส่วนขยายคอมไพเลอร์ / ลิงเกอร์เพื่อแปลงไฟล์เป็นไฟล์ไบนารีพร้อมสัญลักษณ์ที่เหมาะสมซึ่งชี้ไปที่จุดเริ่มต้นและจุดสิ้นสุดของข้อมูลไบนารี ดูคำตอบนี้: รวมแฟ้มไบนารีกับสคริปต์ GNU LD ลิงเกอร์
  2. แปลงไฟล์ของคุณเป็นลำดับของค่าคงที่อักขระที่สามารถเริ่มต้นอาร์เรย์ได้ โปรดทราบว่าคุณไม่สามารถทำ "" และขยายหลายบรรทัดได้ คุณจะต้องมีตัวอักษรต่อเนื่องของบรรทัด ( \), "ตัวหนีและอื่น ๆ เพื่อให้ทำงานได้ ง่ายกว่าเพียงแค่เขียนโปรแกรมเล็กน้อยเพื่อแปลงไบต์เป็นลำดับเช่น'\xFF', '\xAB', ...., '\0'(หรือใช้เครื่องมือ unix ที่xxdอธิบายโดยคำตอบอื่นถ้าคุณมี!):

รหัส:

#include <stdio.h>

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

(ไม่ผ่านการทดสอบ) จากนั้นทำ:

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

ตำแหน่งที่ data.h ถูกสร้างโดย

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

1
บรรทัดสุดท้ายควรอ่าน "cat file.bin | ./bin2c> data.h" หรือ "./bin2c <file.bin> data.h"
Hasturkun

ฉันใช้codeproject.com/Tips/845393/…เพื่อสร้างไฟล์ hex (บน Windows) จากไบนารีแล้วใช้คำแนะนำของคุณในคำchar my_file[] = { #include my_large_file.h };ขอบคุณ!
คนอยู่ที่ไหนสักแห่ง

bin2cคือไม่ bin2c เดียวกับจากเดเบียนhxtoolsระวัง
ThorSummoner

หรือถ้าเป็นเช่นนั้นการอุทธรณ์จะยิ่งใหญ่กว่าเดิมตอนนี้:bin2c -H myoutput.h myinput1.txt myinputN.txt
ThorSummoner

9

ตกลงแรงบันดาลใจจากโพสต์ของ Daeminฉันทดสอบตัวอย่างง่ายๆดังต่อไปนี้:

a.data:

"this is test\n file\n"

test.c:

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

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

ดังนั้นจึงใช้งานได้ แต่ต้องการข้อมูลที่ล้อมรอบด้วยเครื่องหมายคำพูด


นั่นคือสิ่งที่ฉันพูดถึงในคำตอบสุดท้ายของฉัน
Daemin

คำพูดหรือสิ่งที่มันเรียกว่าการให้อภัยของฉันภาษาอังกฤษ
Ilya

สิ่งนี้ต้องการข้อมูลที่จะหนีออกจาก C ฉันไม่คิดว่าเป็นสิ่งที่โพสต์กำลังมองหา หากสิ่งนี้มีมาโครการเรียงลำดับบางอย่างที่ C-escaped เนื้อหาของไฟล์นั้นจะเป็นเรื่องปกติ
Brian Chrisman

8

ฉันชอบคำตอบของ kayahr หากคุณไม่ต้องการสัมผัสไฟล์อินพุตและถ้าคุณใช้CMakeคุณสามารถเพิ่มลำดับอักขระของขอบเขตในไฟล์ได้ ตัวอย่างโค้ด CMake ต่อไปนี้คัดลอกไฟล์อินพุตและล้อมเนื้อหาตาม:

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)

จากนั้นรวมไว้ใน c ++ ดังนี้:

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

5

คุณสามารถทำได้โดยใช้objcopy:

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

myfile.txtตอนนี้คุณมีไฟล์วัตถุที่คุณสามารถเชื่อมโยงเข้าสู่ปฏิบัติการของคุณซึ่งมีสัญลักษณ์สำหรับจุดเริ่มต้นปลายและขนาดของเนื้อหาจาก


1
คุณสามารถบอกเราได้ว่าชื่อสัญลักษณ์จะเป็นอย่างไร
ทำเครื่องหมาย Ch

@MarkCh: ตามเอกสารชื่อสัญลักษณ์จะถูกสร้างขึ้นจากชื่อไฟล์อินพุต
John Zwinck

ฉันเดาว่านี่จะใช้งานได้กับเครื่องที่ไม่ใช่ x86-64 ใช่ไหม?
ThorSummoner


2

คุณจำเป็นต้องฉันxtrยูทิลิตี้ bash scriptแต่คุณสามารถทำมันด้วย bin2incนี่คือที่ผมเรียกสคริปต์ char[] variableพารามิเตอร์ตัวแรกเป็นชื่อของผลลัพธ์ fileพารามิเตอร์ที่สองคือชื่อของ เอาต์พุตคือ C include fileพร้อมเนื้อหาไฟล์ที่เข้ารหัส (เป็นตัวพิมพ์เล็กhex) ตามชื่อตัวแปรที่กำหนด char arrayเป็นzero terminatedและความยาวของข้อมูลที่ถูกเก็บไว้ใน$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")';'

คุณสามารถรับ XTR ได้ที่นี่ xtr (ตัวละคร eXTRapolator) คือ GPLV3


2

หากคุณยินดีที่จะใช้เคล็ดลับสกปรกคุณสามารถสร้างสรรค์ด้วยตัวอักษรสตริงดิบและ#includeสำหรับไฟล์บางประเภท

ตัวอย่างเช่นสมมติว่าฉันต้องการรวมสคริปต์ SQL บางตัวสำหรับ SQLite ในโครงการของฉันและฉันต้องการได้รับการเน้นไวยากรณ์ แต่ไม่ต้องการโครงสร้างพื้นฐานการสร้างพิเศษใด ๆ ฉันสามารถมีไฟล์นี้test.sqlซึ่งเป็น SQL ที่ถูกต้องสำหรับ SQLite ที่--เริ่มความคิดเห็น:

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

แล้วในรหัส C ++ ของฉันฉันสามารถมี:

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

    cout << mysql << endl;
}

ผลลัพธ์คือ:

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

หรือเพื่อรวมรหัส Python บางส่วนจากไฟล์test.pyซึ่งเป็นสคริปต์ Python ที่ถูกต้อง (เพราะ#เริ่มความคิดเห็นใน Python และpassไม่ต้องใช้ op-o):

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

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

แล้วในรหัส C ++:

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

    cout << mypython << endl;
}

ซึ่งจะส่งออก:

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

myfunc()
#undef pass
#define pass

มันเป็นไปได้ที่จะเล่นกลอุบายที่คล้ายกันสำหรับรหัสประเภทอื่น ๆ ที่คุณอาจต้องการรวมเป็นสตริง ไม่ว่าจะเป็นความคิดที่ดีหรือไม่ เป็นแฮ็คที่เรียบร้อย แต่อาจไม่ใช่สิ่งที่คุณต้องการในรหัสการผลิตจริง อาจจะโอเคสำหรับโครงการแฮ็ควันหยุดสุดสัปดาห์


ฉันใช้วิธีนี้เพื่อใส่ OpenGL Shaders ในไฟล์ข้อความด้วย!
yano

1

ฉันนำ xxd ไปใช้ใน python3 อีกครั้งแก้ไขการรบกวนทั้งหมดของ xxd:

  • ความถูกต้อง Const
  • ประเภทข้อมูลความยาวสตริง: int → size_t
  • การยกเลิก Null (ในกรณีที่คุณอาจต้องการ)
  • เข้ากันได้กับสตริง C: วางunsignedบนอาเรย์
  • เอาต์พุตที่เล็กกว่าและอ่านได้ดังที่คุณเขียนไว้: ASCII ที่พิมพ์ได้เป็นเอาต์พุตตามที่เป็น; ไบต์อื่น ๆ มีการเข้ารหัสฐานสิบหก

นี่คือสคริปต์กรองด้วยตัวเองเพื่อให้คุณสามารถดูว่ามันทำอะไร:

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;

การใช้งาน (ซึ่งจะแยกสคริปต์):

#include <stdio.h>

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

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

1

สิ่งที่อาจใช้ได้คือถ้าคุณทำสิ่งที่ชอบ

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

แน่นอนว่าคุณจะต้องระวังสิ่งที่เกิดขึ้นจริงในไฟล์ตรวจสอบให้แน่ใจว่าไม่มีเครื่องหมายอัญประกาศคู่กันว่าอักขระที่เหมาะสมทั้งหมดจะถูกหลบหนี ฯลฯ

ดังนั้นมันอาจจะง่ายกว่าถ้าคุณเพิ่งโหลดข้อความจากไฟล์ตอนรันไทม์หรือฝังข้อความลงในรหัสโดยตรง

หากคุณยังต้องการข้อความในไฟล์อื่นคุณสามารถใส่มันไว้ในนั้นได้ แต่จะต้องมีการแสดงเป็นสตริง คุณจะใช้รหัสข้างต้น แต่ไม่มีเครื่องหมายคำพูดคู่ ตัวอย่างเช่น:

file.txt

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

main.cpp

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

โดยทั่วไปแล้วจะมีสตริงสไตล์ C หรือ C ++ ในไฟล์ข้อความที่คุณรวมไว้ มันจะทำให้ผู้ใช้รหัสเพราะไม่มีข้อความจำนวนมากในตอนเริ่มต้นของไฟล์


3
แนวคิดที่ดี แต่มันใช้งานไม่ได้คุณมีข้อผิดพลาดเนื่องจากตัวอักษรมีบรรทัดใหม่หรือส่วน #include จะถูกอ่านเป็นสตริงและไม่ถูกดำเนินการถูกสาปถ้าคุณทำและถูกสาปถ้าคุณไม่ .. .
Motti

1
@Motti: เห็นด้วย - ตามที่เขียนไว้ไม่ถูกต้อง syntactically C. ความคิดเป็นที่น่าสนใจ - C Pre-Processor เป็นตรรกะแยกขั้นตอน - แต่การปฏิบัติก็คือว่ามันไม่ได้ลงจากพื้นเพราะแต่ละบรรทัดในไฟล์รวมจะมี จะจบลงด้วยเครื่องหมาย ฯลฯ
โจนาธาน Leffler

2
humm ดูเหมือนกับฉันว่าคุณไม่ควรใช้แบ็กสแลชเนื่องจากคอมไพเลอร์ส่วนใหญ่จะต่อสายอักขระที่ต่อเนื่องกันเข้าด้วยกัน
EvilTeach

สิ่งที่มีคำตอบนี้คือ ... ถ้ามันง่ายขนาดนั้นฉันไม่คิดว่า OP จะเคยถามคำถาม! -1 เนื่องจากการมีคำตอบนี้เป็นการกระตุ้นให้ผู้คนเสียเวลาลองสิ่งที่ไม่ทำงาน ฉันคิดว่าเราสามารถลบ downvote หากคุณเปลี่ยน "สิ่งที่อาจทำงาน" เป็น "สำหรับการอ้างอิงนี่ใช้งานไม่ได้"
Mark Ch

@JonathanLeffler หลังจากที่ตัวประมวลผลล่วงหน้ารันแล้วควรเป็น C หรือ C ++ ที่ถูกต้องทั้งนี้ขึ้นอยู่กับการจัดรูปแบบไฟล์.txt
Daemin

0

แม้ว่าจะสามารถทำได้ในเวลารวบรวม (ฉันไม่คิดว่าจะทำได้โดยทั่วไป) ข้อความน่าจะเป็นส่วนหัวที่ประมวลผลล่วงหน้าแทนที่จะเป็นเนื้อหาของคำต่อคำ ฉันคาดว่าคุณจะต้องโหลดข้อความจากไฟล์ตอนรันไทม์หรือทำงาน cut-n-paste ที่น่ารังเกียจ


0

คำตอบของ Hasturkun ที่ใช้ตัวเลือก xxd -i นั้นยอดเยี่ยม หากคุณต้องการรวมกระบวนการแปลง (text -> ไฟล์ hex include) ลงในบิลด์เครื่องมือ / ไลบรารี hexdump.c ของคุณได้เพิ่มความสามารถที่คล้ายกับตัวเลือก xxd's -i โดยตรง (มันไม่ได้ให้ส่วนหัวเต็ม - คุณต้องการ เพื่อให้นิยาม char array - แต่นั่นมีข้อดีของการให้คุณเลือกชื่อของ array char:

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

สิทธิ์ใช้งานเป็น "มาตรฐาน" มากกว่า xxd และมีความอิสระอย่างมาก - ตัวอย่างของการใช้เพื่อฝังไฟล์ init ในโปรแกรมสามารถดูได้ในไฟล์ CMakeLists.txt และ schema ที่นี่:

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

มีทั้งข้อดีและข้อเสียในการรวมไฟล์ที่สร้างในซอร์สต้นไม้และชุดบันเดิลยูทิลิตี้ - วิธีจัดการมันจะขึ้นอยู่กับเป้าหมายและความต้องการเฉพาะของโครงการของคุณ hexdump.c เปิดตัวเลือกการรวมสำหรับแอปพลิเคชันนี้


0

ฉันคิดว่ามันเป็นไปไม่ได้กับคอมไพเลอร์และประมวลผลเดี่ยว gcc อนุญาตสิ่งนี้:

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

แต่น่าเสียดายที่ไม่ใช่:

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

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

ข้อผิดพลาดคือ:

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

ฉันมองตามที่คุณเสนอราคาให้ฉันดู ฉันไม่เห็นข้อมูลใหม่ในคำตอบของคุณ (ข้อมูลที่ไม่ได้อยู่ในคำตอบอื่น ๆ ) นอกเหนือจากการอ้างอิงถึง/etc/hostnameเป็นวิธีการฝังชื่อของเครื่องสร้างในสตริงซึ่ง (แม้ว่ามันจะทำงาน) จะไม่ แบบพกพาตั้งแต่ Mac OS X /etc/hostnameไม่ได้มีไฟล์ โปรดทราบว่าการใช้ชื่อแมโครที่เริ่มต้นด้วยเครื่องหมายขีดล่างตามด้วยตัวพิมพ์ใหญ่คือการใช้ชื่อที่สงวนไว้สำหรับการใช้งานซึ่งก็คือ A Bad Thing ™
Jonathan Leffler

0

ทำไมไม่เชื่อมโยงข้อความเข้ากับโปรแกรมและใช้เป็นตัวแปรทั่วโลก! นี่คือตัวอย่าง ฉันกำลังพิจารณาใช้สิ่งนี้เพื่อรวมไฟล์ Open GL shader ภายในปฏิบัติการได้เนื่องจาก GL shaders จำเป็นต้องรวบรวมสำหรับ GPU ในขณะใช้งานจริง


0

ฉันมีปัญหาที่คล้ายกันและสำหรับไฟล์ขนาดเล็กวิธีแก้ปัญหาดังกล่าวของ Johannes Schaub ทำงานเหมือนมีเสน่ห์สำหรับฉัน

อย่างไรก็ตามสำหรับไฟล์ที่มีขนาดใหญ่ขึ้นเล็กน้อยจะพบปัญหากับการ จำกัด จำนวนอักขระของคอมไพเลอร์ ดังนั้นฉันจึงเขียนแอปพลิเคชั่นตัวเข้ารหัสขนาดเล็กที่แปลงเนื้อหาไฟล์เป็นอาเรย์อักขระสองมิติที่มีขนาดเท่ากัน (และอาจเป็นศูนย์เติมเต็ม) มันสร้าง textfiles เอาท์พุทที่มีข้อมูลอาร์เรย์ 2D เช่นนี้

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

โดยที่ 4 เป็นตัวแปร MAX_CHARS_PER_ARRAY จริงในตัวเข้ารหัส ไฟล์ที่มีรหัส C ที่ได้รับผลตัวอย่างเช่น "main_js_file_data.h" สามารถถูก inline เข้าไปในแอปพลิเคชัน C ++ ได้อย่างง่ายดายตัวอย่างเช่น:

#include "main_js_file_data.h"

นี่คือรหัสที่มาของการเข้ารหัส:

#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

ปัญหานี้ทำให้ฉันรำคาญและ xxd ไม่ทำงานสำหรับกรณีการใช้งานของฉันเพราะมันทำให้ตัวแปรที่เรียกว่า __home_myname_build_prog_cmakelists_src_autogen เมื่อฉันพยายามเขียนสคริปต์ดังนั้นฉันจึงสร้างโปรแกรมเพื่อแก้ไขปัญหานี้:

https://github.com/Exaeta/brcc

มันสร้างไฟล์ที่มาและส่วนหัวและช่วยให้คุณสามารถตั้งชื่อของแต่ละตัวแปรอย่างชัดเจนดังนั้นคุณสามารถใช้พวกเขาผ่าน std :: start (arrayname) และ std :: end (arrayname)

ฉันรวมไว้ในโครงการ cmake ของฉันเช่น:

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)

ด้วยการปรับแต่งเล็ก ๆ ฉันคิดว่ามันสามารถทำงานกับ C ได้เช่นกัน


-1

ใน xh

"this is a "
"buncha text"

ใน main.c

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

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

    return 0
}

ควรจะทำงาน


สำหรับหลายบรรทัดคุณต้องเพิ่ม \ n ดังนั้น: "บรรทัด 1 \ n" "บรรทัด 2 \ n"
Superfly Jon

บิตทำให้เข้าใจผิดอย่างเห็นได้ชัดนี้ต้องเตรียมความพร้อมของแฟ้มข้อความบางอย่างเพื่อเพิ่มราคาและ \ n ตัวอักษรไม่ทำงานในกรณีทั่วไป
มาร์ค Ch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.