2017-02-15 8 views
-1

私は現在、以下のようにCで新しいString構造体を作成しており、ポインタ演算を練習中です。構造体を使ったCのポインタ演算

struct String { 
    uint32_t check; 
    uint32_t capacity; 
    uint32_t length; 
    char data[1]; 

} String; 

と私はどのように私のSTRINGマクロ作品を理解し、それが正常に動作しますが、私は私のif文がない理由はかなりわからないコード

define STRING(s) ((String*)(s - 3*sizeof(uint32_t))) 

void utstrfree(char* self) { 

// if(*(self - sizeof(uint32_t) * 3) == SIGNATURE) WHY DOES THIS NOT >WORK? 

    assert((STRING(self)->check) == SIGNATURE);  //check if it's a >utstring 

    free(self-sizeof(uint32_t) * 3); //properly free the malloc and alternative could have been free(STRING(self)) 

} 

のこの部分で少し混乱していました作業。誰も私にこれを説明することはできますか?

+0

トピックを外してください:現代スタンダードCでは、このマジックリサイズ 'struct'トリックコーシャーですか? – user4581301

+1

@ user4581301現代Cは、charデータ[1];ではなく、柔軟な配列メンバ - char data []; 'を使用する必要があります。そうでなければ、char *魚のような、しかし、非常にタイプセーフではない)。 – PSkocik

+2

いいえ、@ user4581301、それ以前の標準ではそれほど正気ではありませんでしたが、実際は通常は動作します*。最近の標準では、[柔軟な配列メンバー](http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p18)を介してこのようなことを直接サポートしています。 –

答えて

2

@AslakBerbyが既に観察されたように、私は作業を行うと仮定していますあなたのアサーションの式は、あなたのコメントアウトされたif文の条件式と同等ではありません。特に、selfchar *であるので、式*(self - sizeof(uint32_t) * 3)はタイプcharであり、式STRING(self)->checkはタイプuint32_tである。後者を評価すると動作が全く定義されていないと仮定すると、前者は後者の最初のバイトのみをシステム固有の格納順序で返します。

全体的に、しかし、この一般的なスキームは全く機能しない程度に、それは脆く、安全ではありません:

  • それは実装が満足する必要はありませんタイプstruct Stringの表現についての仮定を行います。
  • これは、配列境界を日常的にオーバーランし、したがって未定義の動作を呼び出します。
  • インプレース部分文字列を表現するメカニズムはありません。
  • 標準ライブラリの文字列関数との十分な相互運用性を提供し、ユーザーが実際に提供するよりも大きな相互運用性を期待します。

勧告:

  • 構造体の中の相対的な位置の計算にoffsetof()に依存しています。それはより安全で明瞭です。
  • 平文char配列文字列との直接の相互運用性を試さないでください - これらのオブジェクトを実際のものとして扱います。結局のところ、そのような練習のポイントは、データ構造そのものではなく、O(1)バージョンstrlen()のような改良された機能です。これらのオブジェクトの使用を標準ライブラリの機能に合わせるために、あなたの道を離れる必要はありません。
  • オブジェクトに直接データを埋め込む代わりに、データへのポインタを使用することを検討してください。これは確かにサイズ変更に対応する優れた役割を果たし、インプレース部分文字列もサポートすることができます。
  • オブジェクトに直接データを埋め込む場合は、柔軟な配列メンバーを使用してください。
1

まあ、ifはマクロと同じではありません。あなたはそれを入力する必要がある場合には、このようなものでなければならない:あなたはあなたが作成し、ポインタを型キャストする必要が

if(((String*)(self - 3*sizeof(uint32_t)))->check) == SIGNATURE) ... 

、その後、あなたが探している属性を使用します。

+0

特に、 'self'が' char * 'であると仮定すると、' if'文は 'char' *を' SIGNATURE'と比較します。それは彼が意図するものではないようです。 –

+0

はい。そして、「署名」がどのように定義されているのかわからないので、どうしてそうは言えないのですか。しかし、彼はこれを行うことができます: 'if(*(unit32_t *)(self-3 * sizeof(uint32_t)))== SIGNATURE)'また動作するはずです。 –

関連する問題