Way on c&c++メモ[三]


単純ではないデータ型を続行します.
昨日は「筆を動かす」ことなく、「東周列国志」を読む考えが芽生え、2章Joelが書いた「ソフトウェア随想録」を見て、少し感銘を受けた.今日再び学んだ道を固める.
オペレーティングシステムでは、ある実行期間内の関数(またはメモリを占有する他のキャリア)が共存しない現象を利用する「オーバーライド」という考え方または技術がある.例えば、次の表では、mainはl-fun()またはr-fun()を呼び出すことができるが、両者を同時に呼び出すことはない.同様に、ll−fun()とrr−fun()も同じ期間に共有されない.すなわちl-fun()とll-fun()はmainの左子孫であり、r-fun()とrr-fun()はmainの右子孫であり、1本の活動木を形成し、あるノード間の消滅順序関係がある:あるノードの左兄弟(もしあれば)はいつもそのノードより先に消滅し、活動記録の先出桟に対応するhttp://blog.csdn.net/jasonblog/archive/2010/01/27/5261634.aspx).
メイン関数main
l-fun();
r-fun();
ll-fun();
rr-fun();
l-funとr-funが共存しない以上、memSize=max(l-fun.memSize,r-fun.memSize)を取る.すなわち、両者の中でメモリが大きい者のメモリに必要な大きさを取ることで、両者が1枚のメモリを共用することができる.ll−funとrr−funも同様である.
このような考えは、共用体と共有メモリを思わず連想させた.
共通体は構造体と似ていますが、構造内のメンバー変数には独立したメモリ空間があり、共通体はすべてのメンバー変数が共通のメモリ空間であり、メモリ要件が最も大きいメンバー変数に必要な大きさと等しく、共通体メンバーにアクセスするたびにヘッダアドレスを取得します.両者の違いは以下の表を参照してください.
 
構造体:
……
num
score
str
……
 
コモン:
……
num,score,str
……
 
別の方法でコードで見ることもできます.
#include <stdio.h>
 
struct sData {
       int num;
       floatscore;
       charstr[20];
};
 
union uData {
       int num;
       floatscore;
       charstr[20];
};
 
int main(int argc, char *argv[]){
       structsData sVar1;
       unionuData uVar1;
       printf("%d,%d/n",sizeof(sVar1) ,sizeof(uVar1));
       printf("%02x/t",&sVar1.num);
       printf("%02x/t",&sVar1.score);
       printf("%02x/n",sVar1.str);
       printf("%02x/t",&uVar1.num);
       printf("%02x/t",&uVar1.score);
       printf("%02x/n",uVar1.str);
       return 0;
}

上記のコードの出力は次のとおりです.
28,20
12f3a4  12f3a8  12f3ac
12f3c0  12f3c0  12f3c0
出力から、1つは、複数のメンバー変数の場合、共通体に必要なメモリ空間の大きさが構造体に比べて小さいことである.2つ目は、構造体の各メンバーには独立したメモリ空間(すなわち、独立したヘッダアドレスがある)があり、共通体のすべてのメンバー変数のヘッダアドレスは、前例のように12 f 3 c 0である.
共用体の1つの応用は私にとても印象的で、それはPHPの弱いタイプの実現です.次の2つのコードは、一定の関連と比較を形成します.
コード1:
#include <stdio.h>
#include <string.h>
 
union uData {
       int num;
       floatscore;
       charstr[20];
};
 
int main(int argc, char*argv[]){
       unionuData var;
       var.num = 1;
       var.score = 1.1;
       strcpy(var.str, "hello");
       return 0;
}

コード2:
<?php
    $var = 1;
    $var = 1.1;
    $var= "hello";

私はこのような比較を通じて、自分の頭の中でどのように強いタイプのC言語で弱いタイプのPHP言語を実現するかを初歩的に確立しました.もっと深く進むには少しzendを開きます.hのカーテン.
phpでは、変数の情報は1つの構造体で統一される.zval_structを保存します.以下は5.3.1ソースコードから抜粋したコードクリップです.
struct_zval_struct {
       /* Variableinformation */
       zvalue_value value;           /* value */
       zend_uint refcount__gc;
       zend_uchar type;       /* active type */
       zend_uchar is_ref__gc;
};

コメントでは、変数値を保存するのはvalueであり、zvalue_であることがわかります.valueタイプの変数.このタイプの定義はzend.hの位置はちょうど_zval_structの上:
typedef union _zvalue_value {
       longlval;                                   /* long value */
       doubledval;                       /* double value */
       struct {
              char*val;
              intlen;
       } str;
       HashTable *ht;                         /* hash tablevalue */
       zend_object_value obj;
}zvalue_value;

明らかにzvalue_valueは共通体タイプの変数です.これは強いタイプのC言語がどのように弱いタイプのPHP言語を実現するかについての少しの浅い知識ですが、この点の浅い知識は私に非常に深い印象を与えて、私に設計思想が非常に重要だと感じさせて、私も非常に欠けています.
共用体は一時的に一段落し、C言語の古典的なタイプ:ポインタに移行します.
私の理解の中で、メモリは1棟のビルのようで、各ビルはメモリのユニットのようで、ドアの番号はメモリの住所のようで、ビルの中の物事はメモリのユニットの記憶の内容で、ポインタは、ドアの番号のようです.例えば、int*pという声明があります.これは、不動産にナンバープレートを専門に保管する部屋を要請し、この部屋に保管されているナンバープレートはintタイプのデータを保管する部屋を指さなければならないことを示しています.
以下に、いくつかのポインタタイプを示します.
int *p;pはintタイプの変数を指すポインタであることを示す.
int * *p;pはポインタ変数を指し、後者はintタイプ変数を指すポインタであることを示す.
int *p[5];配列pの要素がポインタであることを示す.
int (*p)[5];pをポインタとして表し,a[][5]のような二次元配列を指す.
int *f();fはポインタタイプの値を返す関数であることを示す.
int (*f)(); fは、関数エントリを指すポインタであることを示す.
共通体が私にその印象的な応用に対して、ポインタも浅い足跡を残しました.それは括弧、void、関数、ポインタの結合です:(*(void(*)()0).初めて見た衝撃的な気持ちは今でも記憶に新しい.まず法則を導入してみましょう.
The right-left rule:
Start reading the declarationfrom the innermost parentheses, go right, and then go left. When you encounterparentheses, the direction should be reversed. Once everything in theparentheses has been parsed, jump out of it. Continue till the wholedeclaration has been parsed.
以上はポインタタイプを判断する有効な手段であり,大まかには最も奥の括弧から始まり,右後左から解析を開始し,括弧に遭遇すると転向することを意味する.上記の例で分析します.
まず、一番奥の括弧を見ると「(*)」が見え、この括弧がポインタを表していることを初歩的に知ることができます.次に飛び出して、まず右に行ってから左に見ると「(*)()」を分析することができて、上のいくつかのポインタのタイプに照らして、私たちは更にこのポインタが1つの関数の入り口を指していることを知ることができます;right-leftを続行すると、ポインタが指す関数の戻り値がvoidタイプであることがわかります.次のステップでは注意深く右を見ると、数字0が見えます.これは、数値0をvoidタイプの関数入口を指すポインタ(少し拗ねています^^)に強制的に変換することを意味します.括弧に出会った後、左を行き来して見ると、星番号「*」が見えますが、星番号がポインタの前に置かれているのはポインタ変数が指す内容を表しています.そこで、このとき、関数エントリアドレス(このエントリアドレスは0)を取得しました.次に最後に,式全体の機能がエントリアドレスが0の関数を呼び出すことであることを知ることができる.より深く理解するために、コード形式で理解しています.
まず、次のコードを見ます.
#include <stdio.h>
 
void greet(){
       printf("hello/n");
}
 
int main(int argc, char*argv[]){
       void(*fp)();
       fp = greet;
       (*fp)();   //   :fp();
       printf("%02x/n",*fp);      //  ,        :printf("%02x/n", fp);
       return 0;
}

上記fpは、関数のエントリを指すポインタであり、関数のエントリアドレスが格納されているため、*fpは関数のエントリアドレスである.次に、そのしびれた式を真似てコードを修正します.
#include <stdio.h>
 
void greet(){
       printf("hello/n");
}
 
int main(int argc, char*argv[]){
       void(*fp)();
       fp = greet;
       (*fp)();   //   :fp();
       printf("%02x/n",*fp);      //           , *fp   
       (*(void(*)())(*fp))();    //!!    
       return 0;
}

実行結果は次のとおりです.
hello
401050
hello
プログラムはgreet関数を2回呼び出し,1回はfpポインタでエントリアドレスを取得して呼び出し,もう1回はその「不思議」な式を模倣していることがわかる.
2010-1-29夜
----------------------------------------cuttingline----------------------------------------