Cポインタシリーズ1

7403 ワード

言叶そのものについて言えば、C/C++は本当に怖いです!最近大体javaとpythonを見て、使うのが本当に便利だと感じて、具体的な方向の上で確かに私に多くのことを省くことができて、例えば簡単な推薦システムあるいはデータマイニングの上で、それでも、比較的に分析のポインタが好きです.レベルが限られているため、まだ机械の学习に関する博文をよく书くことができません.だから、ここではまずC指针に対する认识を新たにします.レベルがあまりにも悪いので,間違いは是正してほしい.
(1)ポインタの本質
ポインタの概念といえば、変数アドレスを格納する変数、4バイト(32ビットマシン)という言葉が頭に浮かぶ.実際、理論概念といえば、プログラミング言語では、内蔵型でもカスタム型でもADT(抽象データ型)とみなすことができ、int型は[-2^32,2^32-1]の範囲に制限されたデータ集合であるなど、いくつかの規則といくつかの操作を定義することができる.また、制限された操作(加算、減算、乗算、除算など)もあり、同理ポインタは独特のデータ型と見なすことができ、加算、減算などの演算を行うことができる.理論が終わったら、逆アセンブリを利用してポインタの実質を認識する.
ポインタ変数はアドレスを格納する変数にすぎない.ではなぜintやfloat型などのポインタ変数があるのでしょうか.ポインタタイプを特定する文が対応する最下位コードに隠されているのではないでしょうか.(以下「//」と表記したコードは逆アセンブルコード)
1 int i;

2 void main()

3 {  

4    int *pi = &i;//    1

5   // C7 05 C0 74 41 00 BC 74 41 00 mov    dword ptr [_pi(4174C0h)],offset _i (4174BCh)

6 }    

逆アセンブリのコードから見ると、文1は単純に&i(変数iのアドレス0 x 4174 BC)を[0 x 4174 C 0](piアドレスにマークされたメモリセル)に格納する--このとき、piの値は0 x 4174 BC(iのアドレス)とする.現在、piがint型ポインタ変数であることをマークする文はまったくありません.文(float*pf=&f)を書いていても.よし、探究を続けろ!!!
  
ポインタ変数のタイプを識別する文はありません.ポインタとは、アドレスを格納するための4バイト変数ではありません.C/C++に現れるint*、float*などはどのように確定しますか?ポインタの強制的な変換はどうなっているのでしょうか.これらの問題は一つ一つ答えなければなりませんね.
確かに、ポインタ変数は4バイトのサイズで、他の変数を格納するためのアドレスです.どこかにポインタのタイプが表示されているに違いないが、私たちは知らないだけだ!!!(次のコードの下線マークの箇所に注意)
 1 int i;

 2 short s;

 3 int *pi;

 4 short *ps;

 5 int main()

 6 {

 7    pi = &i;

 8     //C7 05 74 71 41 00 68 71 41 00 mov         dword ptr [_pi (417174h)],offset _i (417168h)

 9    *pi = 12;

10     //A1 74 71 41 00   mov         eax,dword ptr [_pi (417174h)]

11    ps = &s;

12     //C7 05 64 71 41 00 42 71 41 00 mov         dword ptr [_ps (417164h)],offset _s (417142h)

13    *ps = 18;

14    /* B8 12 00 00 00     mov         eax,12h

15       8B 0D 64 71 41 0   mov         ecx,dword ptr [_ps (417164h)]

16       66 89 01           mov         word ptr [ecx],ax 

17   */

18 }

もともと、ポインタタイプを識別する文は存在せず、メモリにアクセスしたときにのみ「強調」され、dword(double word)--4バイト、word-2バイトである.すなわち、int型ポインタで4バイトの読み取り/書き込みが可能であり、short型ポインタで2バイトの読み取り/書き込みしかできない.すなわち、ポインタ変数自体のタイプがメモリにアクセスするバイト数を決定する.では強制的に変換するとどんな変換がありますか??
(2)ポインタの強制的な変換
  
次に最も簡単なコードを並べて、ポインタの強制的な変換時に何が起こったのかを分析しやすい(ここではコードを逆アセンブリしていない)
 1 int main()

 2 {

 3   int i = 0x00001234; 

 4   char *pc =(char*)&i;//char *pc = &i        

 5   printf("i = %x
",*pc);// 6 /* 7   short j = 0x5678; 8   int *pi =(int*)&j; 9   *pi = 12;// ? 10 */ 11 return 0; 12 }

ここでは、下位優先プラットフォームの下、すなわち、下位バイトの34がメモリの中で最下位ビットに格納されていると仮定します(表が挿入されないため、具体的なメモリ構造図は示されません).上記のプログラムの実行結果*pc=34(16進数)、次の注釈のプログラムの実行でエラーが発生します.
ポインタ強制変換操作については、ポインタの強制的な変換は「詐欺」にすぎないとまとめた.「コンパイラの取り組みは、プログラムコードをコンパイラの法眼から逃れることができるだけです.しかし、コンパイラ段階を通じて決して安心できる理由ではありません.ポインタの強制的な変換には特別な操作はありません.単純なアドレス割り当てにすぎません.ポインタを利用してメモリにアクセスするときに本格的に使用されます.ポインタの本来のタイプがポインタアクセスを決定します.メモリのバイト数(強制変換後も同じ)、pcは&i強制変換で割り当てられた値であっても1バイトしかアクセスできません.ok...付与後のpc保存は変数iのアドレスであり、*pc操作はiのアドレスに基づいて指向するメモリセルにアクセスするが、pcのタイプによって1バイトしかアクセスできないことが決定されるため、結果は34 hとなる.
次のプログラムの実行はなぜ間違っているのでしょうか.piはint型ポインタであるため、piを利用してメモリを読み書きする場合、そのアクセスメモリサイズは4バイトである.short型オブジェクトアドレスをpiに強制的に付与しましたが、ここで間違いがありますか?もちろんありません...少なくともコンパイラはあなたを通過させます...本当に問題になったのは*pi=12で、解引用操作はpiが格納したアドレス(ここでは&j)に基づいて、対応するメモリユニットを見つけます.注意:piの値に基づいてjが格納されているメモリユニットを見つけて、12を格納します.(元のデータはもちろん上書きされています)...Ops...int型ポインタですね.私がアクセスするのは4バイトです.もちろん0 x 00000000 cを入力します.jは2バイトしかありません.「未知」のバイトを2つ借りるしかありません(なぜ「未知」と呼ばれていますか).どうですか.私たちはその2バイトのデータがゴミなのか宝物なのか分からないので、未知の行為は危険で、実行時に通過できない可能性があります.