組み込みでこそC++を使う10の理由
Upcoming SlideShare
Loading in...5
×
 

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

on

  • 9,574 views

 

Statistics

Views

Total Views
9,574
Views on SlideShare
8,842
Embed Views
732

Actions

Likes
10
Downloads
24
Comments
2

5 Embeds 732

http://ryo021021.hatenablog.com 711
https://twitter.com 18
https://si0.twimg.com 1
http://feedly.com 1
https://www.google.co.jp 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • ビットシフトがあるとうまく投稿できなかったので省かせていただきました。
    Are you sure you want to
    Your message goes here
    Processing…
  • 22 ページの gen_mask についてですが、正しくは
    static const T value = (~static_cast(0) ・・・
    ではないでしょうか?(頭の符号反転が不要)
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

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