そろそろC++やるぞパート24 演算子 「sizeof」「後置++, --」
そろそろC++やります
そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。
という感じでやっています。
※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。
内容
- 今回は「sizeof演算子」と「後置インクリメント/デクリメント」を行っていきます。
sizeof 演算子 sizeof
構文
sizeof unary-expression sizeof ( type-name )
char
のサイズに対する相対的になサイズが返されます。char
のサイズは基本的に1となっています。
演算結果としてsize_t
が返されます。
int i = 100; size_t si = sizeof(i); cout << si << endl; long l = 100; size_t sl = sizeof(l); cout << sl << endl;
Output
4 8
sizeof
を重ねて、こういうこともできます。
int i = 100; size_t si = sizeof(i); size_t s = sizeof(sizeof(sizeof(sizeof(sizeof(si)))));
配列の要素数の取得
sizeof array / sizeof array[0]
sizeof array は配列に使用しているメモリ全て、 sizeof array[0] は配列の型の大きさを表します。
int ar[2] = {13, 17}; size_t arSize = sizeof(ar) / sizeof(ar[0]); cout << arSize << endl;
Output
2
前置インクリメント/デクリメント演算子: ++
. --
構文
++ unary-expression -- unary-expression
後置インクリメント/デクリメントと同様に、1単位分増減させます。
int i = 100; cout << i << endl; ++i; cout << i << endl; --i; cout << i << endl;
Output
100 101 100
前置と後置の違い
同じ「1単位分増減させる」演算子ですが、それぞれ定義されていることには理由があります。それが、評価と使用の順番です。それぞれこのようになっています。
前置 インクリメント/デクリメント
- 評価
- 使用
後置インクリメント/デクリメント
- 使用
- 評価
何を意味しているのかソースコードで見てみます。
int i = 100; int j = i++; cout << i << endl; cout << j << endl; int i2 = 100; int j2 = ++i2; cout << i2 << endl; cout << j2 << endl;
Output
101 100 101 101
int j = i++;
のところは先にint j = i;
として代入されて、使用された後にi++
が評価されて101に変わります。
一方で、int j2 = ++i2;
は先に++i2
が評価されて101になって、int j2 = 101;
となり、j2
は101になります
アセンブリ
前置と後置でコンパイルした結果を見てみます。以下の2つのソースコードで試します。
main.cpp
#include <iostream> using namespace std; int main() { int i = 100; int j = i++; }
main2.cpp
#include <iostream> using namespace std; int main() { int i = 100; int j = ++i; }
コンパイルには-S
をつけてアセンブリに、ファイルの比較にはdiff
コマンドを使用します。
$ diff main.cpp main2.cpp 7c7 < int j = i++; --- > int j = ++i; $ g++ -S main.cpp -o a.s $ g++ -S main2.cpp -o b.s $ diff a.s b.s 13,14c13,14 < add w9, w8, #1 < str w9, [sp, #12] --- > add w8, w8, #1 > str w8, [sp, #12]
アセンブリにした時に差分は2行現れました。これだけでは分かりにくいので、前後を少し取り出してみます。
a.s
mov w8, #100 str w8, [sp, #12] ldr w8, [sp, #12] add w9, w8, #1 str w9, [sp, #12] str w8, [sp, #8]
- 100を
w8
レジスタに入れる w8
レジスタの内容を#12
に保存#12
の内容をw8
レジスタに読み込みw8
と 1 を足した値をw9
に入れるw9
レジスタの内容を#12
に保存w8
レジスタの内容を#8
に保存
b.s
mov w8, #100 str w8, [sp, #12] ldr w8, [sp, #12] add w8, w8, #1 str w8, [sp, #12] str w8, [sp, #8]
- 100を
w8
レジスタに入れる w8
レジスタの内容を#12
に保存#12
の内容をw8
レジスタに読み込みw8
と 1 を足した値をw8
に入れるw8
レジスタの内容を#12
に保存#8
の内容をw8
レジスタに読み込み。
後置インクリメントの場合は、w9
レジスタに値に計算した値を一度入れています。#12
にはインクリメントされた101、#8
にはインクリメント前の100が入っている状態になります。
このように少し違いがあるので使用する際には注意が必要です。
参考リスト
感想
インクリメントとデクリメントが間違えずに使わないとエラーが出そうです。sizeof演算子はあまり使わないと思います。配列の要素数もこれを用いて求めるよりは初期化した値を取っておく方がよいかなと思いました。
次回も引き続き演算子を行おうと思います。