組み込みでこそc++を使う10の理由

32
組み込みでこそ C++を使う100の理由 Aiming 大阪社内勉強会 2012-06-11 @kikairoya

Upload: kikairoya

Post on 14-Jun-2015

13.224 views

Category:

Technology


7 download

TRANSCRIPT

Page 1: 組み込みでこそC++を使う10の理由

組み込みでこそ

C++を使う100の理由

Aiming 大阪社内勉強会

2012-06-11 @kikairoya

Page 2: 組み込みでこそC++を使う10の理由

喋ること

• C滅びろ

• C滅びろ

• C滅びろ

• C滅びろ

• C滅びろ

Page 3: 組み込みでこそC++を使う10の理由

「Cを使う必然性」の幻想

• C++使うと遅くなるしCでいいよ

• …同じならCでよくね?

• いや例外とかでかいじゃん

• templateとかよくわかんないし

Page 4: 組み込みでこそC++を使う10の理由

C++使うと遅くなるしCでいいよ

• そうでもない

• 同じことを実現しようとすれば、ほぼ正確に同じだけの命令数が必要

– Cで書いてもC++で書いても生成コードサイズは大して変わらない(RTTIと例外テーブルは除く)

• 20年前の昔なら兎も角、21世紀も10年過ぎた現在ではJavaですらCより速い場合がある

Page 5: 組み込みでこそC++を使う10の理由

「C++遅い」の主要因

• 無意味な仮想関数

– dynamic polymorphismを使わないなら要らない

• newの乱発

– Cと同じように単にスタックに配置すればいい

• SjLj例外ハンドリング

– Dw2例外ハンドリングを使うか、OFFにする

Page 6: 組み込みでこそC++を使う10の理由

おまけ:Javaのパフォーマンス

• http://blog.cfelde.com/2010/06/c-vs-java-

performance/ とか

g++ 4.3

vs

Sun Java HotSpot VM, version 1.6.0_20

Page 7: 組み込みでこそC++を使う10の理由
Page 8: 組み込みでこそC++を使う10の理由
Page 9: 組み込みでこそC++を使う10の理由

…同じならCでよくね?

• んなこたない

• C++でしか出来ないことはあるけれど、Cでしか出来ないことはほとんど無い

– C99の複合リテラル・名前付き初期化くらい

– どちらもC++で似たような機能は実現可能

– C89に限定すれば事実上「全く」無いと言える

Page 10: 組み込みでこそC++を使う10の理由

いや例外とかでかいじゃん

• そげなことない

• 不要ならOFFにすればいいだけ

• RTTIも同様

• 例外飛ばしてたらリアルタイム性守れない場合があるので、その場合はOFF

• 例外無くてもデストラクタは正しく走るので、リソース管理も安全安心

Page 11: 組み込みでこそC++を使う10の理由

templateとかよくわかんないし

• 面倒な部分はライブラリ側に全部隠せます

• エラーコードは確かに量多いですが… 実行時に不思議な挙動をするか コンパイル時に説教されるか どっちがいいですか?

• コンパイル通した時点でデバッグ終了が理想

–現実は厳しいけれど、コンパイラが見つけてくれるエラーの量はCとは段違い

Page 12: 組み込みでこそC++を使う10の理由

便利で危険なprintf

• printfって便利だけど危ないよね…

• sizeof(int)==2の環境だと特に問題が顕在化しやすい

• それC++なら型安全に出来るよ

• ntfmtとか

• cprintfとか

Page 13: 組み込みでこそC++を使う10の理由

printfの罠

• たとえばこんなコード

extern int g_value_for_something;

void logger() {

printf("value:%d¥n",

g_value_for_something);

}

Page 14: 組み込みでこそC++を使う10の理由

printfの罠

• 「intが16ビットですぐ溢れるからlongにしよう」

extern long g_value_for_something;

void logger() {

printf("value:%d¥n",

g_value_for_something);

}

Page 15: 組み込みでこそC++を使う10の理由

printfの罠

• 「intが16ビットですぐ溢れるからlongにしよう」

extern long g_value_for_something;

void logger() {

printf("value:%d¥n",

g_value_for_something);

}

!!!フォーマット指定子を変え忘れた!!!

Page 16: 組み込みでこそC++を使う10の理由

constexprなprintfなら

• 変え忘れたらコンパイルエラーにできます

extern long g_value_for_something;

void logger() {

cprintf("value:%d¥n",

g_value_for_something);

} FORMAT_ERROR_format_specifier_d_takes_int_but_

given<T>::fail() [with T = long int]

Page 17: 組み込みでこそC++を使う10の理由

void *パレード

• Cで汎用コンテナやアルゴリズム作ろうとすると、void *の山になりますよね…

• ライブラリで閉じていればまだいいけど、ユーザコードでvoid *からキャストする必要がある

• それC++なら型安全に出来るよ

• STLとか

Page 18: 組み込みでこそC++を使う10の理由

ビットフィールドの恐怖

• 組み込みでも一番低いレイヤではハードウェアレジスタを叩く必要がある

• Cだとよくビットフィールド使うけれど…

• GCCでは間違ったアドレスにアクセスすることがある!

Page 19: 組み込みでこそC++を使う10の理由

ビットフィールドの恐怖

• こんなありふれたコードから…

volatile struct {

volatile unsigned int a: 8;

volatile unsigned int b: 4;

} bitfield;

int main() {

bitfield.a = 1;

}

Page 20: 組み込みでこそC++を使う10の理由

ビットフィールドの恐怖

• こんな恐ろしいコードが!!!

movl $1, bitfield+3(%rip)

↑ (bitfield+3)番地に32ビットで書き込み

Page 21: 組み込みでこそC++を使う10の理由

ビットフィールドの恐怖

• 組み込みでも一番低いレイヤではハードウェアレジスタを叩く必要がある

• Cだとよくビットフィールド使うけれど…

• GCCでは間違ったアドレスにアクセスすることがある!(注: BTSにパッチ投稿済)

–ベンダコンパイラでもコンパイルオプション一つでビットオーダーが変わることがある

• それC++なら安全でポータブルに出来るよ

Page 22: 組み込みでこそC++を使う10の理由

ビットフィールドの克服

• こんなコードを用意しておけば…

struct addr_t { size_t addr; };

template <typename T, int H, int L = H>

struct ioaccess_bit {

template <int = bitsizeof(H)-1, int = H>

struct gen_mask {

static constexpr T value = (~static_cast<T>(0)<<H+1) ^ (~static_cast<T>(0)<<L);

};

template <int h>

struct gen_mask<h, h> { static constexpr T value = ~(~static_cast<T>(0) << L); };

constexpr ioaccess_bit(addr_t addr): addr(addr.addr) { }

size_t addr;

// continue

Page 23: 組み込みでこそC++を使う10の理由

ビットフィールドの克服

• こんなコードを用意しておけば…

// continued

size_t addr;

static constexpr T mask = gen_mask<>::value;

constexpr T omit_bits(T x) { return x & ~mask; }

constexpr T extract_bits(T x) { return (x & mask) >> L; }

constexpr T shift_bits(T x) { return (x << L) & mask; }

volatile T *get_addr() const { return reinterpret_cast<volatile T *>(addr); }

operator T() const { return extract_bits(*get_addr()); }

ioaccess_bit operator =(T v) const {

T tmp = *get_addr(); *get_addr() = omit_bits(tmp) | shift_bits(v); return *this;

}

};

Page 24: 組み込みでこそC++を使う10の理由

ビットフィールドの克服

• こんな定義で… struct { struct reg_t { struct can_mb_id_t {

struct bit_t {

static constexpr size_t base = 0x00090200;

size_t offset;

ioaccess_bit<uint32_t, 31> IDE = addr_t{base+offset};

ioaccess_bit<uint32_t, 30> RTR = addr_t{base+offset};

ioaccess_bit<uint32_t, 28, 18> SID = addr_t{base+offset};

ioaccess_bit<uint32_t, 17, 0> EID = addr_t{base+offset};

bit_t(size_t off): offset(off) { }

} BIT;

} ID; };

reg_t operator[] (size_t n) { return reg_t{{{n}}}; }

} MB;

Page 25: 組み込みでこそC++を使う10の理由

ビットフィールドの克服

• こんなコードが書けます。

int n = MB[0].ID.BIT.SID;

MB[0].ID.BIT.EID = 12;

assert(MB[1].ID.BIT.IDE == 1);

Page 26: 組み込みでこそC++を使う10の理由

割り込みマスク

• 割り込みを一時的にマスクしたいこと、有りますよね

• sti()/cli()でいいんだけど、もしネストされてたら…?

• というかcli()とか呼ぶの忘れますよね

• それC++なら自動化できるよ

Page 27: 組み込みでこそC++を使う10の理由

単純な例

struct lock_interrupt {

lock_interrupt() : masked(get_imask_ccr()) {

set_imask_ccr(1);

}

~lock_interrupt() {

set_imask_ccr(masked);

}

bool masked;

};

// in some function...

lock_interrupt lk;

// do critical action, let's forget unmask interrupt flag!

}

Page 28: 組み込みでこそC++を使う10の理由

醜い固定小数点演算

• Cで実数演算する場合は…

– double/floatを使う

–整数を自前でシフトして使う

–固定小数点演算ライブラリを作る

• 固定小数点を使う場合、演算子使えなくて大変ですよね…

• それC++ならスマートに出来るよ

Page 29: 組み込みでこそC++を使う10の理由

美しい固定小数点演算

fixed calc_1(

fixed v,

fixed u

) {

v *= 1.5f;

return v + calc_2(u);

}

void calc_1(

fixed *result,

fixed *pv,

fixed *pu

) {

fixed tmp;

fixed_from_float(&tmp, 1.5f);

fixed_mul(pv, pu, &tmp);

calc_2(&tmp, pu);

fixed_plus(result, pv, &tmp);

}

Page 30: 組み込みでこそC++を使う10の理由

美しい固定小数点演算

• 演算子オーバーロードは用法・容量を守って正しく使いましょう。

Page 31: 組み込みでこそC++を使う10の理由

まずは簡単なところから

• たとえC++の機能を使っていなくても、拡張子は.cpp

にしましょう

• マクロで定数やインライン関数を書くのはやめて、static constやinlineを使いましょう

• テンプレートを「書く」のは慣れてからで十分

• 千里の道も一歩から

C++マスターもBetter Cから

Page 32: 組み込みでこそC++を使う10の理由

おしまい

• Let's C++!!!