22

ファイルに何かを書き込んで(それを と呼びましょうfoo.cpp) 、コンパイル時にプログラムに文字列として含めたいと思い#includeます。

現在、私はこのCプリプロセッサを使用しています#define:

#define toString(src) #src

次の例のように、一連のコードを文字列に変換します。

const char* str = toString(
  int x;
  void main(){}
);

必要に応じて、マクロの文字列化について読むことができます。

そのコードをコンパイル時に「リンク」される外部ファイルに移動したいと思います。 ファイルをプログラムと一緒に配布する必要はありません。これは、実行時にファイルを読み取る場合に当てはまります。

以下に示すようにディレクティブを使用しようとしまし#includeたが、コンパイラはそれを拒否しました:

const char* str = toString(
#include "foo.cpp"
);

g++完全に混乱しているようですが、clang++このエラーが発生しました:

error: embedding a #include directive within macro arguments is not supported

これを行うことができるかどうか、またはどのように行うことができるかを誰かが知っていますか?

注: 私はこれを使用して GLSL シェーダーを作成していますが、この情報が何の役にも立たないとは思えません。

PS:これがこの質問の複製であると私に言う前に、コードを独自のファイルの巨大な文字列に入れるか、外部ツール(例:)を使用xxdして16進表現をダンプすることは、私にとって「解決策」ではありません。私の現在の方法よりも良くない(つまり、簡単/きれい)。


数年後の更新:
重複としてクローズされたため、この質問に答えることができなかったことに気付きました。この commitを見たときに探していた答えが見つかりました。それ自体は、この記事へのコメントに基づいており、それ以来ずっと使用しています。

簡単に言うと、小さなアセンブリ ファイルには必要なファイルが含まれてNAMEおり、3 つの変数を使用して特定の のNAME_begin下に公開され、C コードからその内容にアクセスできますNAME_endNAME_len

xxdこのように、必要なコードだけを含む通常のファイルがあり、実行時に読み取ったり、フープをジャンプしたりする代わりに、コンパイル時に自動的に読み取られます。

4

3 に答える 3

17

あなたが何を達成しようとしているのかよくわかりませんが、Linuxコマンドラインユーティリティxxdがあなたが探しているものかもしれません:

xxd -i [filename]

は、完全なバイナリ エンコーディングのファイル コンテンツを含む配列と、その長さを含む変数を含む C スタイルのヘッダー ファイルを生成します。

例:

xxd -i /proc/cpuinfo

でファイルを作成します

unsigned char _proc_cpuinfo[] = {
  0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x09, 0x3a, 0x20,
  0x30, 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x09,
...
};
unsigned int _proc_cpuinfo_len = 654390;

結果のヘッダーをコードに含め、それらの変数を介して配列とファイルの長さにアクセスできます。

于 2013-10-28T15:23:46.397 に答える
1

このような場合の最も簡単な方法は、ファイルを読み取り、各行を引用符で囲んで出力する小さなプリプロセッサを作成することです。私はおそらく Python でこれを行うでしょうが、C++ でもかなり簡単です。どこかからとを取得したとしますinputFile(おそらくですが、後者の 2 つは入力ファイル名から派生させたい場合があります)。outputFilevariableNameargv

void
wrapFile( std::istream& inputFile,
          std::ostream& outputFile,
          std::string const& variableName )
{
    outputFile << "extern char const " << variableName << "[] =\n";
    std::string line;
    while ( std::getline( inputFile, line ) ) {
        outputFile << "    \"" << line << "\\n\"\n";
    }
    std::outputFile << ";" << std::endl;
}

含めるファイルの内容によっては、出力する前に をマングルして、 や などをエスケープする必要がある場合がありlineます。"\

工夫したい場合は、それ自体の行ではなく、最後のラップされた行にセミコロンを挿入するテストを追加できますが、それは実際には必要ありません。

これにより、'\0'文字列が終了します。文字列の長さの可能性を考えると、長さの 2 番目の変数を追加することが望ましい場合があります。

std::outputFile << "extern int const "
                << variableName
                << "_len = sizeof(" << variableName << ") - 1;\n";

(コンパイラが文字列リテラルに追加する終端をカウントしたくないため、-1 を忘れないでください'\0'。) 生成されたファイルを使用する場所に含める場合、必ずしも必要ではありません。これは、std::beginと が必要な情報を提供するためです (ただし、 を使用して を無視することをstd::end忘れないでください)。std::end( variableName ) - 1'\n'

を使用している場合、生成されたファイルを、ラップされるファイルmake、ラップを行う実行可能ファイルに依存させるのはかなり簡単です(これは、上記のソースなどに依存します)。Visual Studio では、ラッピング コードを C++ で記述する場合 (このために Python を使用する理由の 1 つ)、ラッピング コード用に別のプロジェクトを作成する必要があり、依存関係の管理に問題が生じる可能性があります。Visual Studios は、実際には専門的な作業 (このような手法を使用して大きなコード ブロックが定期的に生成される作業) 向けには設計されていません。

于 2013-10-28T15:49:16.480 に答える