topazの遊び場

いろいろやってみる

そろそろC++やるぞパート7 配列 ~ 導入と定数式 ~

そろそろC++やります

そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。

という感じでやっています。

※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。

内容

  • 配列について触れていく予定が、定数式について実験を行いました。

配列

配列とは、連続したメモリ領域を占領する、同じ方のオブジェクトシーケンスです。 従来のC言語スタイルの配列は、一般的ですが多くのバグの原因となっています。今回登場するCスタイルの配列より、std::arraystd::vectorを使うことをお勧めします。

スタックの宣言

配列の宣言は{型名} {変数名}[要素数]です。基本型も自作定義型も配列にすることができます。

int a[100];
MyClass myClass[100];

要素の数は、整数リテラルまたは定数式で指定する必要があります。
定数式とは
定数式とは、コンパイル時に計算できる式のことです。int a = 13 + 57;があった時に、コンパイル時にint a = 70:にしてくれるようなものです。
(ここからは配列とは関係ない内容です。面白かったのでいろいろやって、長くなりました。)


例えば以下のmain.cppがあったとします。

// main.cpp
int main()
{
    int a = 13 + 57;
    int b = 24 + 37;
    int c = a + b;
    cout << c << endl;
    return 0;
}

これを実行すると131が出力されます。これはプログラムを実行しなくても計算できる値になります。
何が起こっているかアセンブリで確認してみます。M1 MacBookarm64アーキテクチャを使用しています。

$ g++ -S main.cpp

生成されたmain.sの計算該当部分を抜き出してみます。

    mov w8, #70
    stur    w8, [x29, #-8]
    mov w8, #61
    stur    w8, [x29, #-12]
    ldur    w8, [x29, #-8]
    ldur    w9, [x29, #-12]
    add w8, w8, w9

これをみると、70int a = 13 + 57;の計算結果、61int b = 24 + 37;の計算結果ということが分かります。これら計算をコンパイラがやっていて、結果をアセンブリに書いています。このアセンブリの時に計算される式を(13+57や24+37)を定数式と呼びます。
このアセンブリではこのようなことを行っています。

1. w8レジスタに70を書き込む
2. w8レジスタの内容をオフセット-8のメモリにコピーする
3. w8レジスタに61を書き込む
4. w8レジスタの内容をオフセット-12メモリにコピーする
5. オフセット-8の内容を、w8レジスタにロードする
6. オフセット-9の内容を、w9レジスタにロードする
7. w8レジスタとw9レジスタの内容を足して、w8に入れる

このアセンブリを実行してみると、先ほどと同じ結果を得ることができます。

$ g++ main.s
$ ./a.out  
131

このアセンブリは「レジスタに書き込んで、メモリにコピーして、またレジスタにロードする」とずいぶん面倒なことを行っています。
最終的に、「7. w8レジスタとw9レジスタの内容を足して、w8に入れる」ができれば良いので、アセンブリを書き換えて直接レジスタに代入したのを計算に使ってみます。

    mov w8, #70
    mov w9, #61
    add w8, w8, w9

70をw8レジスタに書き込み、61をw9に書き込みますそれを足してw8に書き込みます。

$ g++ main.s 
$ ./a.out 
131

実行しても同じ131が得られたことが分かります。
と、関係ないアセンブリの話に入ってしまいましたが、言いたいことは、定数式はコンパイルしてアセンブリになった時点で、計算された状態になるもの、ということです。
これでいいように思えますが、一度メモリに保存していないということは、変数aの値を失っているということです。今回の場合はこのような最適化が行えましたが、行えない場合もあるので注意が必要です。


脱線してしまいましたが、キリがよいので今回はここで終わりにします。

参考リンク

感想

配列を行うつもりが、定数式について考えていました。今回C++では初めてアセンブリに書き起こしました。久しぶりにアセンブリ見たのですが、やはり少し読める言語を解読しているみたいで楽しですね。

次回は、絶対に配列に入ろうと思います。std::arraystd::vectorも使ってみたいなと思いました。