2017-04-14 4 views
1

私はターゲットのプロセスメモリを変更する必要があるプログラムに取り組んでいます。C - ポインタ算術演算を行うときにuintptr_tとchar *をキャストする理由

これまでのところ、私は住所がを格納するためのvoid *を使用して、私はそれらを変更する必要がある場合、それらはchar *にキャストしています(オフセット追加または一般に変更)

私はstdint.hで定義されているタイプの聞いたことがあるが、私は、char *変換(それは私より多くのC89フレンドリーであると思われる)の上のポインタ算術のためにそれを使用する違いは表示されません

私の質問:これらの両方の方法は、ポインタ演算に使用する必要がありますか?いずれにしてもchar *以上のuintptr_tの使用を検討すべきでしょうか?

EDIT 1

基本的に私はちょうどコードがアドレスを扱っている場合は、次のは正しくない可能性があると指摘。これはコメントユーザーRで

0x00F00BAA hard coded memory adress in target 
process 
void* x = (void*)0x00F00BAA; 
char* y = (void*)0x00F00BAA; 
x = (uintptr_t)x + 0x123; 
y = (char*)y + 0x123; 

x == y? 
x == (void*)0x00F00CCD? 
y == (void*)0x00F00CCD? 
+0

標準では、 'uintptr_t'変数の算術的な変更に続いて' char * 'へのキャストが保証されないと、' char * 'に数学を直接適用するのと同じ結果になります'uintptr_t'は派生したものですが、これが成立しなければ狂っていると思います。 – PSkocik

+0

@PSkocikもちろんそれは成立せず、全く狂っていません。 –

+0

@AnttiHaapala私がuintptr_tを3だけ動かすと、対応するchar *が3で動くことも期待されます。フラットメモリモデルのプラットフォームが何か違うことをしたいのはなぜか分かりません。 – PSkocik

答えて

2

を生み出すかどうかを知る必要があり現在のプロセス内で有効ではありません。私は明確化のためにOPに尋ねた。

コードの移植性を気にしている場合は、ポインタ算術にはuintptr_tを使用しないでください。 uintptr_tは整数型です。その上の算術演算は、ポインタ算術ではなく整数算術です。

値がvoid*で、バイトオフセットを追加する場合は、char*にキャストするのが正しい方法です。

uintptr_tの算術演算はchar*算術と同じように動作する可能性がありますが、絶対に保証されません。 C標準が提供する唯一の保証は、void*の値をuintptr_tに変換して元の値に戻すことができるということです。

標準では、uintptr_tが存在することを保証しません。情報の損失なしに変換されたポインタ値を保持するのに十分な整数型がない場合、実装はuintptr_tを定義しません。

私は実際にはuintptr_tの演算が必ずしも機能しないシステム(Crayベクトルマシン)で作業しました。ハードウェアには64ビットのワードがあり、マシンアドレスにはワードのアドレスが入っています。 UnixライクなOSは8ビットバイトをサポートする必要があったため、バイトポインタ(void*char*)は、64ビットワードの未使用の上位3ビットに格納された3ビットオフセットのワードアドレスを含んでいました。ポインタ/整数変換は単純に表現をコピーします。その結果、char*ポインターに1を加えると、次のバイト(ソフトウェアで処理されたオフセット)を指すが、uintptr_tに変換して1を加えると、次のワードを指し示す。

要点:ポインタ演算が必要な場合は、ポインタ演算を使用します。それがそれのためのものです。

(ちなみに、gccの拡張子はvoid*です。ポータブルコードでは使用しないでください。sizeof (void) == 1などの奇妙な副作用もあります。)

+0

私は 'void *'から 'char *'へのキャストを想定しています。そのようなアーキテクチャでは、ポインタ表現を変換します。しかし、変換で何が起こるのでしょうか?アラインされていない 'char *'を 'void *'トラップに戻すことはできますか? – TrentP

+0

この回答は多分別の質問のために正しいかもしれませんが、OPの質問には完全に間違っています。 OPはポインタ型の使用と、これらのポインタに対するポインタ算術を使って、「ターゲットプロセス」(ある種のデバッグ/メモリ覗き見/ポンキング)のアドレスを格納し操作することを検討しています。このためのポインタの使用は無効です。ポインタは、他のプロセスではなく、プログラム自身のアドレス空間にある既存のオブジェクトを指し示すだけであり、そのオブジェクトに対する算術演算は、指し示されたオブジェクト内にとどまっている限り有効です。 –

+0

さらに、 'uintptr_t'は動作するかもしれませんが(' void * 'の対象となる未定義問題の影響を受けません)、デバッガとターゲットプロセスが同じISA/ABIを使用することを前提としています。この種のソフトウェアを設計する際の前提。代わりに、ターゲットプロセスの(ターゲット実装定義の)ポインタ表現と一致するように選択された整数型を使用してください。 ELFシステムでは、例えば、 'Elf32_Addr' /' Elf64_Addr'のようなタイプが適切です。 –