Publicidad

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

kikairoya
10 de Jun de 2012
Publicidad

Más contenido relacionado

Presentaciones para ti(20)

Publicidad

Último(20)

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

  1. 組み込みでこそ C++を使う100の理由 Aiming 大阪社内勉強会 2012-06-11 @kikairoya
  2. 喋ること • C滅びろ • C滅びろ • C滅びろ • C滅びろ • C滅びろ
  3. 「Cを使う必然性」の幻想 • C++使うと遅くなるしCでいいよ • …同じならCでよくね? • いや例外とかでかいじゃん • templateとかよくわかんないし
  4. C++使うと遅くなるしCでいいよ • そうでもない • 同じことを実現しようとすれば、ほぼ正確に同じだけ の命令数が必要 – Cで書いてもC++で書いても生成コードサイズは 大して変わらない(RTTIと例外テーブルは除く) • 20年前の昔なら兎も角、21世紀も10年過ぎた現在 ではJavaですらCより速い場合がある
  5. 「C++遅い」の主要因 • 無意味な仮想関数 – dynamic polymorphismを使わないなら要らない • newの乱発 – Cと同じように単にスタックに配置すればいい • SjLj例外ハンドリング – Dw2例外ハンドリングを使うか、OFFにする
  6. おまけ:Javaのパフォーマンス • http://blog.cfelde.com/2010/06/c-vs-java- performance/ とか g++ 4.3 vs Sun Java HotSpot VM, version 1.6.0_20
  7. …同じならCでよくね? • んなこたない • C++でしか出来ないことはあるけれど、Cでしか出来 ないことはほとんど無い – C99の複合リテラル・名前付き初期化くらい – どちらもC++で似たような機能は実現可能 – C89に限定すれば事実上「全く」無いと言える
  8. いや例外とかでかいじゃん • そげなことない • 不要ならOFFにすればいいだけ • RTTIも同様 • 例外飛ばしてたらリアルタイム性守れない場 合があるので、その場合はOFF • 例外無くてもデストラクタは正しく走るので、リ ソース管理も安全安心
  9. templateとかよくわかんないし • 面倒な部分はライブラリ側に全部隠せます • エラーコードは確かに量多いですが… 実行時に不思議な挙動をするか コンパイル時に説教されるか どっちがいいですか? • コンパイル通した時点でデバッグ終了が理想 – 現実は厳しいけれど、コンパイラが見つけ てくれるエラーの量はCとは段違い
  10. 便利で危険なprintf • printfって便利だけど危ないよね… • sizeof(int)==2の環境だと特に問題が顕在化 しやすい • それC++なら型安全に出来るよ • ntfmtとか • cprintfとか
  11. printfの罠 • たとえばこんなコード extern int g_value_for_something; void logger() { printf("value:%d¥n", g_value_for_something); }
  12. printfの罠 • 「intが16ビットですぐ溢れるからlongにしよう」 extern long g_value_for_something; void logger() { printf("value:%d¥n", g_value_for_something); }
  13. printfの罠 • 「intが16ビットですぐ溢れるからlongにしよう」 extern long g_value_for_something; void logger() { !!!フォーマット指定子を変え忘れた!!! printf("value:%d¥n", g_value_for_something); }
  14. 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]
  15. void *パレード • Cで汎用コンテナやアルゴリズム作ろうとする と、void *の山になりますよね… • ライブラリで閉じていればまだいいけど、ユー ザコードでvoid *からキャストする必要がある • それC++なら型安全に出来るよ • STLとか
  16. ビットフィールドの恐怖 • 組み込みでも一番低いレイヤではハードウェ アレジスタを叩く必要がある • Cだとよくビットフィールド使うけれど… • GCCでは間違ったアドレスにアクセスすること がある!
  17. ビットフィールドの恐怖 • こんなありふれたコードから… volatile struct { volatile unsigned int a: 8; volatile unsigned int b: 4; } bitfield; int main() { bitfield.a = 1; }
  18. ビットフィールドの恐怖 • こんな恐ろしいコードが!!! movl $1, bitfield+3(%rip) ↑ (bitfield+3)番地に32ビットで書き込み
  19. ビットフィールドの恐怖 • 組み込みでも一番低いレイヤではハードウェアレジ スタを叩く必要がある • Cだとよくビットフィールド使うけれど… • GCCでは間違ったアドレスにアクセスすることがあ る!(注: BTSにパッチ投稿済) – ベンダコンパイラでもコンパイルオプション一つで ビットオーダーが変わることがある • それC++なら安全でポータブルに出来るよ
  20. ビットフィールドの克服 • こんなコードを用意しておけば… 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
  21. ビットフィールドの克服 • こんなコードを用意しておけば… // 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; } };
  22. ビットフィールドの克服 • こんな定義で… 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;
  23. ビットフィールドの克服 • こんなコードが書けます。 int n = MB[0].ID.BIT.SID; MB[0].ID.BIT.EID = 12; assert(MB[1].ID.BIT.IDE == 1);
  24. 割り込みマスク • 割り込みを一時的にマスクしたいこと、有りますよね • sti()/cli()でいいんだけど、もしネストされてたら…? • というかcli()とか呼ぶの忘れますよね • それC++なら自動化できるよ
  25. 単純な例 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! }
  26. 醜い固定小数点演算 • Cで実数演算する場合は… – double/floatを使う – 整数を自前でシフトして使う – 固定小数点演算ライブラリを作る • 固定小数点を使う場合、演算子使えなくて大変です よね… • それC++ならスマートに出来るよ
  27. 美しい固定小数点演算 fixed calc_1( void calc_1( fixed v, fixed *result, fixed u fixed *pv, ){ fixed *pu v *= 1.5f; ){ return v + calc_2(u); fixed tmp; } fixed_from_float(&tmp, 1.5f); fixed_mul(pv, pu, &tmp); calc_2(&tmp, pu); fixed_plus(result, pv, &tmp); }
  28. 美しい固定小数点演算 • 演算子オーバーロードは用法・容量を守って 正しく使いましょう。
  29. まずは簡単なところから • たとえC++の機能を使っていなくても、拡張子は.cpp にしましょう • マクロで定数やインライン関数を書くのはやめて、 static constやinlineを使いましょう • テンプレートを「書く」のは慣れてからで十分 • 千里の道も一歩から C++マスターもBetter Cから
  30. おしまい • Let's C++!!!
Publicidad