0

私は現在Cでパーサーを書いていますが、それを設計するときに必要なものの1つは、可変文字列「クラス」(インスタンスを表す不透明な構造体を操作する関数のセット)でしたmy_stringchar *文字列クラスのインスタンスは、いくつかのメタデータとともに、をラップする構造体にすぎません。

ただし、定数文字列では問題が発生します。たとえば、my_string *ポインタを返すメソッドがいくつかありますが、定数文字列を返したい場合があります。この不自然な擬似コードを考えてみましょう。

my_string *element_get_data(my_element *el)
{
    if (element_has_character_data(el))
        return element_get_character_data(el); /* returns a (my_string *) */
    else
        return my_string_constant("#data");    /* ditto */
}

…場合によっては、ビルド済みのインスタンスをフェッチしたい場合もあれば、構造体my_stringにラップされた文字列「#data」を返したい場合もありますmy_string

このコードの問題は、が呼び出されるmy_stringたびに新しい(ヒープに割り当てられた)インスタンスが作成されることです。element_get_data(...)C定数文字列は、プログラムのDATAセクションに静的に割り当てられるという点で優れたセマンティクスを備えているため、定数文字列が検出されるたびに、その文字列のアドレスは常に同じになります。

したがって、いくつかの異なるmy_stringインスタンスがすべてまったく同じを指しているのはばかげているようchar *です。これを重複排除する効率的な方法は何ですか?const char * -> my_string *マッピングのハッシュテーブルを保持する必要がありますか?または、C定数文字列と同様のセマンティクスを使用する方法はありますか?Macでは、CoreFoundationはCFSTR(...)マクロを使用してこれを実行できます。

私にとって理想的な解決策my_string_constant(...)は、プログラムのDATAセクションに構造体を格納するようなマクロを作成するmy_stringことです。これも一定である可能性があります。そのようなことは可能ですか?

4

1 に答える 1

1

私がこの質問を書いている間(というより、私が終わった直後に)、GNUStepのCore FoundationのCFSTR()マクロの実装の形で私の質問に対する答えを見つけました。私の同様の実装は次のようになります。

#define MY_STR(str) ({\
    static struct { const char *buffer; my_bool shouldFree; my_bool mutable; my_bool constant; } s = {NULL, MY_FALSE, MY_FALSE, MY_TRUE};\
    s.buffer = str;\
    (my_string *)&s;\
})

これが機能する理由は、コードのブロックがコンパイル時にインライン化されるためです。つまり、ローカルスコープに対して静的に割り当てられた構造体が作成されます。したがって、(たとえば)を含む関数がMY_STR("Hello, world!")複数回呼び出された場合、静的に割り当てられた同じ構造体が常に返され、目的の動作が得られます。

この概念は、文字列などを超えて簡単に拡張できるため、静的に割り当てられた独自のオブジェクトタイプを簡単に作成できます。きちんとした!

于 2013-02-08T04:48:51.333 に答える