2009-06-12 4 views
2

目的私はに対応(タイプvoid *の)そのパラメータかどうかを伝えることができます機能と同様のmalloc/reallocを/無料のラッパー関数を提供し、より大きなプロジェクトのための小さなライブラリを書いていますCのポインタへのバイトレベルアクセスにはどのような移植性の問題が関係していますか?

ライブラリーのラッパー関数によって割り当てられて管理されるライブ(未だ解放されていない)メモリー。この関数をisgood_memoryと呼んでみましょう。

内部的に、ライブラリは、isgood_memoryによって実行される検索が確実に高速であることを保証するために、ハッシュテーブルを維持します。ハッシュテーブルは、ポインタ(タイプvoid *の要素)を維持して検索を可能にします。明らかに、値は追加され、ハッシュテーブルから削除されて、割り当てられたものと解放されたものとをそれぞれ最新の状態に保つ。

ライブラリの移植性が私の最大の関心事です。 C90(ISO/IEC 9899:1990)に準拠した環境のみを想定して設計されています。

質問

ポータビリティが私の最大の関心事であるので、私はハッシュ関数のためにそのsizeof(void *) == sizeof(X)を負いませんでした。したがって、値を文字列であるかのように扱います。これを達成するために、ハッシュ関数は少し似ています:

static size_t hashit(void *ptrval) 
{ 
    size_t i = 0, h = 0; 
    union { 
     void *ptrval; 
     unsigned char string[sizeof(void *)]; 
    } ptrstr; 

    ptrstr.ptrval = ptrval; 

    for (; i < sizeof(void *); ++i) { 
     size_t byte = ptrstr.string[i]; 

     /* Crazy operations here... */ 
    } 

    return (h); 
} 

この特定のフラグメントにはどのような移植性の問題がありますか? ptrvalバイト単位でアクセスすると、うんざりしたアライメントの問題が発生しますか?

+0

エンディアンが問題になる可能性があります。 – cobbal

+0

プログラム内でのハッシングのためだけであるため、エンディアンは固定されており、どのエンディアンが適用されるかは関係ありません。 –

+0

私はリトルエンディアンプラットフォームからビッグエンディアンプラットフォーム(私がアクセスできるSun Microsystemsサーバー)に移植しました。すべてが正常に動作しているようです。 –

答えて

1

ここで行うように、unsigned charの配列としてデータ型にアクセスできます。私が見る主要な移植性の問題は、特定の場所を特定するビットパターンがユニークでないプラットフォームで発生する可能性があります。その場合、ビットパターンが異なるため、等しいハッシュと異なる場所を比較するポインタが得られる可能性があります。

どうして違うのですか?まあ、一つのこととして、ほとんどのCデータ型は値に関与しないパディングビットを含むことが許されています。そのようなパディングビットを含むポインタが、同じ場所を指し示すパディングビット内でのみ異なる2つのポインタを有することができるプラットフォーム。 (例えば、OSはポインタの機能を示すためにいくつかのポインタビットを使用するかもしれませんが、物理アドレスだけではありません)。もう一つの例はfarポインタがsegment:offsetで構成されたDOSの初期のfarメモリモデルです。セグメントは重複しているので、segment:offsetはsegment + 1:offset-xと同じ場所を指すことができます。

今日、一般的に使用されているほとんどのプラットフォームでは、特定の場所を指すビットパターンは実際にはユニークです。したがって、厳密に準拠しているとは考えにくいにもかかわらず、コードは広く移植可能になります。

+0

このようなプラットフォームの合理的なサイズのリストをコンパイルすることは可能ですか? Googleの検索で私を助けてくれるような定義的な特徴がありますか? –

+0

ポインタのビットパターンが一意ではないプラットフォームのリストが必要ですか?一般的に、Windows、Solaris、HP-UX、LinuxなどのOSを実行する主流のワークステーションのようなプラットフォームでは、アドレス空間と固有のビットパターンがフラットな傾向があります。埋め込みの世界や実験的なマシンでは、より多くのカスタムハードウェアを手に入れることができ、状況は異なる場合があります。 Cの標準ではこのようなプラットフォームを使用できますが、現在使用されているプラ​​ットフォームの数はわかりません。 – dewtell

+0

(これは愚かな質問かもしれませんが、私は確信が必要です)AとBの2つのポインタ値(void *型の両方)を持っているとしましょう。同じ根底にあるビットパターンですが、実際にはメモリ内の異なる場所を参照していますか? –

1

かなりきれいに見えます。 C99のヘッダ<inttypes.h>に頼ることができる場合は、uintptr_tを使用することを検討してください。ただし、値をバイト単位でハッシュしたい場合は、バイト単位に分割することになり、実際の利点はありません。それ。

+0

uintptr_tを定義するC99ヘッダーファイルは、ではなくです。 にはを含めるように指定されています。 は、タイプimaxdiv_tと、さまざまな整数タイプのprintf/scanfで使用されるフォーマット指定子のためのいくつかのマクロを定義します。 –

+0

にはが含まれており、を持たない場合はがあり、ではなく、である可能性があります。しかし、はい、あなたは正しいです、あなたはちょうどを持っているなら、は必要ありません。 –

1

大体正しい。しかし、1つの潜在的な問題があります。あなたに割り当てます

size_t byte = ptrstr.string[i]; 

*文字列は、unsigned charではなくcharとして定義されています。 charsとunsigned size_tを署名したプラットフォームでは、あなたが期待するかもしれない、あるいは期待していない結果を与えるでしょう。あなたのcharをunsigned charに変更すれば、それはより洗練されたものになります。

+0

この度はありがとうございます。それは面白いです...私は実際に私のコードでは、署名されていないcharを持っていたが、私はここでそれを入力したときに署名なしを残しました。上記のコード断片を修正しました。 –

0

割り当てられたメモリを追跡する以外にポインタ値を必要としない場合は、ハッシュテーブルを完全に取り除き、以下の例のように割り当てられたメモリと共にマジックナンバーを格納してください。割り当てられたメモリの横に存在するマジックナンバーは、それがまだ「生きている」ことを示します。メモリを解放するときは、メモリを解放する前に、保存されているマジックナンバーを消去します。

#pragma pack(1) 
struct sMemHdl 
{ 
    int magic; 
    byte firstByte; 
}; 
#pragma pack() 

#define MAGIC 0xDEADDEAD 
#define MAGIC_SIZE sizeof(((struct sMemHdl *)0)->magic) 

void *get_memory(size_t request) 
{ 
    struct sMemHdl *pMemHdl = (struct sMemHdl *)malloc(MAGIC_SIZE + request); 
    pMemHdl->magic = MAGIC; 
    return (void *)&pMemHdl->firstByte; 
} 

void free_memory (void *mem) 
{ 
    if (isgood_memory(mem) != 0) 
    { 
     struct sMemHdl *pMemHdl = (struct sMemHdl *)((byte *)mem - MAGIC_SIZE); 
     pMemHdl->magic = 0; 
     free(pMemHdl); 
    } 
} 

int isgood_memory (void *Mem) 
{ 
    struct sMemHdl *pMemHdl = (struct sMemHdl *)((byte *)Mem - MAGIC_SIZE); 
    if (pMemHdl->magic == MAGIC) 
    { 
     return 1; /* mem is good */ 
    } 
    else 
    { 
     return 0; /* mem already freed */ 
    } 
} 

0

ポータビリティビューからではない問題に文字や符号なし文字などの整数またはポインタを変数へのアクセス...これは少しハックかもしれないが、私はハック気分に思いますよ。しかし、それはハードウェアに依存するため、その逆は真ではありません。 私は1つの質問があります。ポインタをハッシュ値(uintptr_tを使用)として使用する代わりに、文字列としてポインタをハッシュしているのはなぜですか?

+0

uintptr_tはC90(ISO/IEC 9899:1990)で利用できますか? –

+0

uintptr_tは標準C90の一部ではありませんが、多くのコンパイラでサポートされており、stdint.hに定義されています。 – bill

+0

大規模なプロジェクトはC90標準に準拠しています。 –

関連する問題