문제

는 방법이 있을 포함하는 전체 텍스트 파일에 문자열로에서는 C 프로그램 컴파일까?

다음과 같습니다.

  • file.txt:

    This is
    a little
    text file
    
  • 습니다.c:

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

를 얻은 작은 프로그램 인쇄하는 표준"이 작 텍스트 파일로"

순간에 나는 사용 hackish python 스크립트,하지만 그것은 엉덩이 추하고 제한하는 단 하나의 변수 이름을 말해 줄 수 있는 다른 방법으로 할 수 있나요?

도움이 되었습니까?

해결책

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

다른 팁

질문에 대 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)====="

두 가지 가능성이 있습니다.

  1. 컴파일러/링커 확장자를 사용하여 파일을 이진 파일로 변환하고 이진 데이터의 시작과 끝을 가리키는 적절한 기호로 파일을 바이너리 파일로 변환하십시오. 이 답변을 참조하십시오 : GNU LD 링커 스크립트가 포함 된 이진 파일을 포함하십시오.
  2. 파일을 배열을 초기화 할 수있는 일련의 문자 상수로 변환하십시오. "" "를 할 수는 없습니다. 라인 연속 문자가 필요합니다 (\), 탈출하다 " 캐릭터와 다른 사람들이 그 일을하게합니다. 바이트를 시퀀스로 변환하기 위해 작은 프로그램을 작성하는 것이 더 쉽습니다. '\xFF', '\xAB', ...., '\0' (또는 유닉스 도구를 사용하십시오 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

좋아요, 영감을 받았습니다 데민의 Post I는 다음과 같은 간단한 예를 테스트했습니다.

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

따라서 작동하지만 견적 표시로 둘러싸인 데이터가 필요합니다.

나는 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"
;

효과가있는 것은 다음과 같은 일을하는 것입니다.

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

물론 실제로 파일에있는 내용에주의를 기울여야합니다. 이중 인용문이없고 모든 적절한 문자가 탈출하는 등

따라서 런타임에 파일에서 텍스트를로드하거나 텍스트를 코드에 직접 포함 시키면 더 쉬울 수 있습니다.

다른 파일의 텍스트를 원한다면 거기에 텍스트를 가질 수 있지만 문자열로 표시해야합니다. 위와 같이 코드를 사용하지만 이중 인용문이 없습니다. 예를 들어:

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

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

당신은 내 필요합니다 xtr 유틸리티이지만 a로 할 수 있습니다 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 (문자 외삽 제)은 GPLV3입니다

당신은 이것을 사용하여 할 수 있습니다 objcopy:

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

이제 컨텐츠의 시작, 끝 및 크기에 대한 기호가 포함 된 실행 파일에 연결할 수있는 객체 파일이 있습니다. myfile.txt.

Python3에서 XXD를 다시 구현하여 XXD의 모든 성가심을 고정했습니다.

  • Const 정확성
  • 문자열 길이 데이터 유형 : int → size_t
  • NULL 종료 (원하는 경우)
  • C 문자열 호환 : 드롭 unsigned 배열에서.
  • 더 작고 읽기 쉬운 출력은 다음과 같이 작성했을 것입니다. 인쇄 가능한 ASCII는 출력입니다. 다른 바이트는 16 진수로 인코딩됩니다.

다음은 스크립트가 자체적으로 필터링되므로 다음과 같은 것을 볼 수 있습니다.

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

컴파일 시간에 수행 할 수 있더라도 (일반적으로 할 수는 없다고 생각합니다) 텍스트는 파일 내용이 구두로 대신 전처리 된 헤더 일 것입니다. 런타임에 파일에서 텍스트를로드하거나 불쾌한 Cut-N-Paste 작업을 수행해야합니다.

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
}

일을해야합니다.

XXD -I 옵션을 사용한 Hasturkun의 답변은 훌륭합니다. 전환 프로세스 (텍스트 -> hex 포함 파일)를 빌드에 직접 통합하려면 HexDump.c 도구/라이브러리를 최근 XXD의 -I 옵션과 유사한 기능을 추가했습니다 (전체 헤더를 제공하지 않아도됩니다. Char Array 정의를 제공하려면 숯 배열의 이름을 선택할 수있는 이점이 있습니다) :

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

라이센스는 XXD보다 훨씬 "표준"이며 매우 자유 롭습니다. 프로그램에 INNT 파일을 포함시키는 데 사용하는 예는 cmakelists.txt 및 scheme.c 파일에서 볼 수 있습니다.

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

소스 트리에 생성 된 파일을 포함시키는 장단점과 묶음 유틸리티가 있습니다. 처리 방법은 프로젝트의 특정 목표와 요구에 따라 다릅니다. HexDump.c는이 응용 프로그램의 번들링 옵션을 열어줍니다.

컴파일러와 사전 처리기만으로는 불가능하다고 생각합니다. 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"

텍스트를 프로그램에 연결하여 글로벌 변수로 사용하십시오! 여기 예입니다. 런타임에 GPU에 대해 GL 셰이더를 컴파일해야하므로 실행 파일 내에 열린 GL 셰이더 파일을 포함시키기 위해 이것을 사용하는 것을 고려하고 있습니다.

나는 비슷한 문제가 있었고, 작은 파일의 경우 위에서 언급 한 Johannes Schaub의 솔루션은 저에게 매력처럼 일했습니다.

그러나 조금 더 큰 파일의 경우 컴파일러의 문자 배열 제한에 문제가 발생했습니다. 따라서 파일 컨텐츠를 동일한 크기의 덩어리 (및 아마도 패딩 0)의 2D 문자 배열로 변환하는 작은 인코더 응용 프로그램을 작성했습니다. 다음과 같은 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입니다. 예를 들어 "main_js_file_data.h"와 같은 결과 C 코드가있는 파일은 다음과 같이 C ++ 응용 프로그램에 쉽게 인쇄 할 수 있습니다.

#include "main_js_file_data.h"

Encoder의 소스 코드는 다음과 같습니다.

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

If you're willing to resort to some dirty tricks you can get creative with raw string literals and #include for certain types of files.

For example, say I want to include some SQL scripts for SQLite in my project and I want to get syntax highlighting but don't want any special build infrastructure. I can have this file test.sql which is valid SQL for SQLite where -- starts a comment:

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

And then in my C++ code I can have:

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

    cout << mysql << endl;
}

The output is:

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

Or to include some Python code from a file test.py which is a valid Python script (because # starts a comment in Python and pass is a no-op):

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

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

And then in the C++ code:

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

    cout << mypython << endl;
}

Which will output:

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

myfunc()
#undef pass
#define pass

It should be possible to play similar tricks for various other types of code you might want to include as a string. Whether or not it is a good idea I'm not sure. It's kind of a neat hack but probably not something you'd want in real production code. Might be ok for a weekend hack project though.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top