0

ANSI C89/ISO C90 の void-pointer 値の上限と下限を移植可能に決定する方法はありますか? (私は現在、標準のコピーを持っていません(家に持っています)。もちろん、void-pointer の値が署名されていないことが保証されている場合、このタスクは簡単です(sizeof(void *) を介して);しかし、私はできませんこれが保証されているかどうか思い出してください. いくつかの非常に非効率なアルゴリズム (オーバーフローするまでインクリメントするなど) を思いつくことができます.これらの境界を計算します。)

- 編集 -

また、ポインター値の有効性を判断する移植可能な方法はありますか?

理由:これは同僚との話し合いの中で出てきたもので、私は困惑しました。彼が何をしているかわからないけど、興味があるから知りたいだけ!:-)

4

6 に答える 6

4

指定されたポインタが有効かどうかを判断する移植可能な方法はありません。扱っているメモリシステムの種類を知る必要があります。オペレーティング システムとプロセッサによっては、仮想メモリ マネージャーのページ テーブルを照会してポインターの有効な範囲を判断する方法がある場合とない場合があります。

たとえば、Linux では、mmap下にある特殊ファイルを調べて/proc、プロセスの仮想メモリ マップを取得できます。cat独自のメモリ マップを読み取る例を次に示します。

$ 猫 /proc/self/mmap
08048000-0804c000 r-xp 00000000 09:00 5128276 /ビン/猫
0804c000-0804d000 rw-p 00003000 09:00 5128276 /ビン/猫
0804d000-0806e000 rw-p 0804d000 00:00 0 [ヒープ]
f7ca7000-f7e40000 r--p 00000000 09:00 3409654 /usr/lib/locale/locale-archive
f7e40000-f7e41000 rw-p f7e40000 00:00 0
f7e41000-f7f68000 r-xp 00000000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f68000-f7f6d000 r--p 00127000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f6d000-f7f6f000 rw-p 0012c000 09:00 2654292 /lib/tls/i686/cmov/libc-2.3.6.so
f7f6f000-f7f72000 rw-p f7f6f000 00:00 0
f7f83000-f7f85000 rw-p f7f83000 00:00 0
f7f85000-f7f9a000 r-xp 00000000 09:00 2637871 /lib/ld-2.3.6.so
f7f9a000-f7f9c000 rw-p 00014000 09:00 2637871 /lib/ld-2.3.6.so
ff821000-ff836000 rw-p 7ffffffea000 00:00 0 [スタック]
ffffe000-fffff000 r-xp ffffe000 00:00 0 [vdso]

メモリが (r)readable、(w)ritable、e(x)ecutable、または (p)resent (つまり、ディスクにページアウトされていない) かどうかを示すビットと共に、有効なポインターの範囲を確認できます。

于 2009-01-22T19:05:04.157 に答える
0

Win32では、64ビットポインタが符号拡張されていることを私は知っています。拡張ポインタに署名しない場合は、64ビットマシンから32ビットミニダンプを検査するのは楽しいことです。

Win32で64ビットポインタ()がどのように機能するかについては、こちらを参照してください。POINTER_64

于 2009-01-22T19:00:09.597 に答える
0

void *メモリ内の実際のビット パターンから、a をキャストできる整数値を識別する必要があります。a をvoid *整数型にキャストすると、変換が必要になる場合があります。

を仮定するとsizeof(void *) == sizeof(long)、 avoid * pの場合、次のことは間違っている可能性があります。

((long)p) == *((long *)&p)

また、標準では、すべての有効なポインターの値を保持するのに十分な大きさの整数型あるかどうかさえ指定されていません!

したがって、やりたいことを実行するための移植可能な方法はありません...

于 2009-01-22T19:28:33.033 に答える
0

NULL に対応する領域を除いて、メモリ アドレスに (移植可能な) 制限はまったくありません。十分に強化された OS は、さまざまな CPU/OS メカニズムを利用して、malloc() の呼び出しごとにランダムで十分に分散されたアドレスを各プロセスに提供し、位置に依存しない実行可能ファイルと ASLR により、任意のアドレスからコードを実行することもできます。

于 2009-01-23T03:32:42.277 に答える
0

ポインターは、仕様によって符号なしであることが保証されています。しかし、一体なぜ境界を見つけたいのでしょうか? 「0x00000001 と 0xffffffff の間のすべて」は、有効なポインターの数がその小さなサブセットになるため、実際には有用なテストではありません。

于 2009-01-22T18:43:07.727 に答える
0

void * は常に、アドレス可能なメモリへのポインターを保持するのに十分な大きさです。それ以外の使用は、メジャー リーグ野球協会によって固く禁じられています。

例: dec-10 は、36 ビット ワードの 36 ビット アーキテクチャでした。それでもアドレスは 18 ビットで、任意のレジスタ/ワードに 2 つのポインタを保持できました。

ええ、それは極端な例です。ポインターを使用して計算を行う必要がある場合は、sizeof が有効です。しかし、連続した配列以外でポインター計算を行うことは、危険というより危険です。

最後に、オブジェクトへのポインターまたは C++ のメンバーへのポインターを格納するために「void *」を使用しないでください。多くのコンパイラ実装では、実際には複数の「物理」ポインターを使用して、具体的な (または部分的に具体的な) クラスの複数の継承を実装しています。実際には、このように多重継承を使用する人はほとんどいないため、これが発生することはほとんどありません。それが起こったとき、何が起こったのかを理解するのは本当に難しい.

于 2009-01-22T19:15:22.483 に答える