ノートンを叩いて砕く話の続き

 windowsC++コンパイラ(g++)を使っています。

f:id:y_saionji:20210511170227p:plain

 今回はノートンは関係ないですし、何も叩いて砕きません。

 ポインタ遊び第二弾です。

 

    char hoge[5] = {1,0,0,0,1};

 こんな感じの配列を用意しました。で、何がしたいかというと、char(1バイト変数型)で定義されたはずのこの配列を先頭から順に4バイト変数型であるint型(あくまで私の環境では4バイト)で読み込んでやろうという話です。

(なぜ4バイトのintで読むのに配列の長さを5にしたかというのはまた後の話。今はhoge[4]は無いものだと思って大丈夫です。)

 

どうやって?

→もちろんポインタで

 

まずint型用のポインタを用意します。

    int *hogege_p;

(補足)なぜhoge_pではなくhogege_pという名前にしたかというと、やはり型が違うためhogeとは明確に区別したかっただけです。もしかしたらこの先、配列hogeの先頭を指すポインタが必要になるかもしれませんからね、その時のためにhoge_pという名前はとっておきます(結局使いませんでしたけど)。(hogege_pじゃなくて他のもっといい名前あっただろ.........)

 

で、あとは分かりますね。このhogege_pに配列hogeの先頭のアドレスを代入します。

    hogege_p = (int*)hoge;

"hoge"はhoge[0]を指す「char型を指すポインタ型」であるので、int*型への型キャストが必要になります。

 

全体のコードは次の通り。

#include <stdio.h>

int main(){
    char hoge[5] = {1,0,0,0,1};
    int *hogege_p;
    hogege_p = (int*)hoge;

    printf("%x\n"hogege_p);
    printf("%d", *hogege_p);

    return 0;
}

出力は

61fe13
1

となりました。

 

あと、対照実験とは言えないですけど、似たようなことをしました。

まぁ、hogeの初期化の内容を変えただけです。

    char hoge[5] = {0,0,0,1,1};

出力は次のようになりました。

61fe13
16777216

 

 

これで何がわかるかというと、int型は若いアドレス(?)を低い桁に持ってきているということです。自分がその辺の知識が無いのが悪いんですが、あくまで私の環境ではこうだというだけであることに注意してください。

例えば、

  1 2 3 4 5 6 7 8  
0x600000                 hoge[0]
0x600001                 hoge[1]
0x600002                 hoge[2]
0x600003                 hoge[3]

 

こんなふうにアドレスとビットが並んでいて、&piyo == 0x600000であるようなint型変数piyoがあったとするなら、0x600000の8から0x600003の1という方向にビットを、2^0, 2^1, 2^2, ... 2^31という順番で読んでいくわけですね。(同一アドレス内のビットの方向までは知りませんが、すくなくともアドレスの方向はこれで合ってるはずです。)

 

実際のアドレスは違いますが、要は

    char hoge[5] = {1,0,0,0,1};

の場合は上の表の0x600000の8のビットが1で他すべてが0だったため、hogege_pの指す値が1になって、

    char hoge[5] = {0,0,0,1,1};

の場合は上の表の0x600003の8のビットが1で他がすべて0だったため、hogege_pの指す値が2^24 = 16777216になった、ということですね。

 

先に「char(1バイト変数型)で定義されたはずのこの配列を先頭から順に4バイト変数型であるint型(あくまで私の環境では4バイト)で読み込」みたい、と述べましたが、実は真の目的は違います。

本当は、配列hogeを先頭からじゃなくて2番目や3番目から読んでメチャクチャな数字を出したかっただけです。

なのでアドレスを1バイトずらす必要があります。hogege_pにアドレスを代入するところで、こうします。

    hogege_p = (int*)(hoge + 1);

"hoge"は正しくはhoge[0]を指すポインタですので、(hoge + 1)はhoge[0]のアドレスの次のアドレス、つまりhoge[1]を指すわけです。

 

 

こうして晴れて、真の目的は達成されるわけです。

#include <stdio.h>

int main(){
    char hoge[5] = {1,0,0,0,1};
    int *hogege_p;

    hogege_p = (int*)hoge;
    printf("%x\n"hogege_p);
    printf("%d\n\n", *hogege_p);

    hogege_p = (int*)(hoge + 1);
    printf("%x\n"hogege_p);
    printf("%d", *hogege_p);

    return 0;
}

出力は

61fe13
1

61fe14
16777216

となりました。メチャクチャな数字を出したいと言いましたが、ここでは理解してもらうために、さっき表で説明した内容で理解できる数値を出力するようにしました。

 

なにか疑問や修正すべきことなど何でも良いので、あればTwitterの西園寺やきしゃも(このブログのアイコンと同じアイコンのアカウント)まで

 

最終話