149

コンパイル時にテキスト ファイル全体を文字列として C プログラムに含める方法はありますか?

何かのようなもの:

  • ファイル.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);
    }
    

標準出力に出力する小さなプログラムを取得する「これは小さなテキスト ファイルです」

現時点では、ハックっぽい python スクリプトを使用しましたが、これは見栄えが悪く、変数名が 1 つしかないため、別の方法を教えてもらえますか?

4

21 に答える 21

148

これには (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;
于 2009-01-04T13:56:22.530 に答える
124

質問は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)====="
于 2014-07-29T17:32:52.093 に答える
14

次の 2 つの可能性があります。

  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
于 2009-01-04T13:57:55.930 に答える
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;
}

したがって、機能していますが、引用符で囲まれたデータが必要です。

于 2009-01-04T21:33:40.860 に答える
2

私のxtrユーティリティが必要ですが、bash script. これは私が呼び出すスクリプトですbin2inc。最初のパラメーターは、結果の名前ですchar[] variable。2 番目のパラメーターは、の名前ですfile。出力は、与えられた変数名としてinclude file(小文字で) エンコードされたファイルの内容を持つCです。hexchar arrayzero 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 です

于 2012-12-10T03:48:42.420 に答える
2

テキストをプログラムにリンクして、グローバル変数として使用してみませんか! ここに例があります。GLシェーダーは実行時にGPU用にコンパイルする必要があるため、これを使用してOpen GLシェーダーファイルを実行可能ファイルに含めることを検討しています。

于 2014-09-11T05:24:18.297 に答える
1

これは、Visual C++ で使用するハックです。次のビルド前イベントを追加します (file.txt が入力で、file_txt.h が出力です)。

@(
  echo const char text[] = R"***(
  type file.txt
  echo ^^^)***";
) > file_txt.h

次に、必要な場所に file_txt.h を含めます。

先頭に \n を追加し、最後に \n^ を追加するため、これは完璧ではありませんが、これは問題ではなく、このソリューションのシンプルさが気に入っています。誰かが余分な文字を取り除くことを改善できるなら、それはいいでしょう。

于 2020-12-06T09:47:28.740 に答える
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"
于 2014-04-15T13:59:29.057 に答える
0

次のようなことをするとうまくいくかもしれません

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++ スタイルの文字列を含めます。ファイルの先頭に大量のテキストがないため、コードがすっきりします。

于 2009-01-04T13:45:10.837 に答える
0

コンパイル時に実行できる場合でも (一般的には実行できないと思います)、テキストは、ファイルの内容そのものではなく、前処理されたヘッダーである可能性があります。実行時にファイルからテキストをロードするか、厄介なカットアンドペースト作業を行う必要があると思います。

于 2009-01-04T13:54:40.070 に答える
-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
}

仕事をするべきです。

于 2009-01-04T21:58:26.693 に答える