11 Apr 2015, 06:52

C 言語/C++ における イベントハンドラの定石 (switch/ 関数ポインタ配列/lambda)

はじめに

C/C++ における イベントハンドラの書き方について,定石を整理してみた.

[toc]

前提

<div class="outline-text-3" id="text-unnumbered-2">
  <p>
    以下のようなコードがあるとする.
  </p>

  <p>
    [sourcecode language=&#8221;cpp&#8221; title=&#8221;&#8221; ]<br /> #include <iostream><br /> typedef enum {START, STOP} COMMAND;
  </p>

  <p>
    void check (COMMAND command) {<br /> std::cout << (int) command << " is called" << std::endl; } int main (int argc, char *argv[]) { check (START); check (STOP); return 0; } [/sourcecode] 

    <p>
      出力結果は以下のようになる.
    </p>

    <p>
      [sourcecode language=&#8221;text&#8221; title=&#8221;&#8221; ]<br /> 0 is called<br /> 1 is called<br /> [/sourcecode]
    </p>

    <p>
      この出力結果は以下のようにしたい.
    </p>

    <p>
      [sourcecode language=&#8221;text&#8221; title=&#8221;&#8221; ]<br /> start is called<br /> stop is called<br /> [/sourcecode]
    </p></div> </div> </div> 

    <div id="outline-container-unnumbered-3" class="outline-2">
      <h2 id="unnumbered-3">
        方法
      </h2>

      <div class="outline-text-2" id="text-unnumbered-3">
      </div>

      <div id="outline-container-unnumbered-4" class="outline-3">
        <h3 id="unnumbered-4">
          switch を使う
        </h3>

        <div class="outline-text-3" id="text-unnumbered-4">
          <p>
            一番単純な方法は, switch をつかって, 表示を分岐する
          </p>

          <p>
            [sourcecode language=&#8221;cpp&#8221; title=&#8221;&#8221; ]<br /> void onStart () { std::cout << "start is called" << std::endl; } void onStop () { std::cout << "stop is called" << std::endl; } void check (COMMAND command) { switch (command) { case START: onStart (); break; case STOP: onStop (); break; } } }; [/sourcecode] </div> </div> 

            <div id="outline-container-unnumbered-5" class="outline-3">
              <h3 id="unnumbered-5">
                関数ポインタ配列を使う
              </h3>

              <div class="outline-text-3" id="text-unnumbered-5">
                <p>
                  別の定石は, 関数ポインタ配列をつかう.
                </p>

                <p>
                  [sourcecode language=&#8221;cpp&#8221; title=&#8221;&#8221; ]<br /> #include <iostream>
                </p>

                <p>
                  typedef enum {START, STOP} COMMAND;
                </p>

                <p>
                  void onStart () { std::cout << "start is called" << std::endl; } void onStop () { std::cout << "stop is called" << std::endl; } typedef void (*HANDLER) (); static HANDLER handle_tbl[2] = {&onStart, &onStop}; void check (COMMAND command) { handle_tbl[command] (); } [/sourcecode] </div> </div> 

                  <div id="outline-container-unnumbered-6" class="outline-3">
                    <h3 id="unnumbered-6">
                      lambda をつかう
                    </h3>

                    <div class="outline-text-3" id="text-unnumbered-6">
                      <p>
                        関数テーブルに関数を登録するために, 関数を作成する必要があるけれども, 一行なので, 関数を作成するのは面倒.
                      </p>

                      <p>
                        そんなときは,c++11 からつかえるようになったラムダ式を利用する.
                      </p>

                      <p>
                        [sourcecode language=&#8221;cpp&#8221; title=&#8221;&#8221; ]<br /> #include <iostream><br /> #include <functional>
                      </p>

                      <p>
                        typedef enum {START, STOP} COMMAND;
                      </p>

                      <p>
                        static std::function<void ()> handle_tbl[2] = {<br /> [] (){ std::cout << "start is called" << std::endl;}, [] (){ std::cout << "stop is called" << std::endl;} }; void check (COMMAND command) { handle_tbl[command] (); } int main (int argc, char *argv[]) { check (START); check (STOP); return 0; } [/sourcecode] 

                        <p>
                          やっぱり, これからは関数型の時代だよね!
                        </p></div> </div> </div> 

                        <div id="outline-container-unnumbered-7" class="outline-2">
                          <h2 id="unnumbered-7">
                            Special Thanks
                          </h2>

                          <div class="outline-text-2" id="text-unnumbered-7">
                            <p>
                              この記事によると, switch 型と関数テーブル型では, スピードは変わらないとか.
                            </p>

                            <ul class="org-ul">
                              <li>
                                <a href="http://dixq.net/forum/viewtopic.php?f=3&t=13875">関数ポインタテーブルと switch 文 • C 言語交流フォーラム ~ mixC++ ~</a>
                              </li>
                            </ul>

                            <p>
                              委譲をつかう方法もある (Strategy Pattern)
                            </p>

                            <ul class="org-ul">
                              <li>
                                <a href="http://www7b.biglobe.ne.jp/~robe/pf/pf016.html">プログラマの友 第十六報:イベントハンドリングとデリゲート</a>
                              </li>
                            </ul>

                            <p>
                              C++11 の方法.
                            </p>

                            <ul class="org-ul">
                              <li>
                                <a href="http://qiita.com/shiro_naga/items/5967f6cd1710e7b78677">C++ &#8211; メンバー関数ポインタと配列を使って, メンバー関数を番号で指定して呼び出す方法 &#8211; Qiita</a>
                              </li>
                              <li>
                                <a href="http://kaworu.jpn.org/cpp/std::function">std::function &#8211; C++ 入門</a>
                              </li>
                            </ul>
                          </div>
                        </div>

28 Mar 2015, 23:47

Emacs で C/C++ の開発環境をめちゃガチャパワーアップしたまとめ

はじめに

次の業務が C/C++ をつかいそうなので, Emacs で C/C++ 開発環境を構築してみました.

題名は, なぜかけっこうアクセス数のあった Ruby 編にあやかった.

[toc]

IDE が備えるべき機能

優れた IDE が備えるべき機能と Emacs での代表的な実現方法は以下.

  • シンタックスハイライト/ インデント
    • major-mode
  • 検索・置換
    • たくさんあるよ.
  • タグジャンプ
    • gtags
    • ggtags
  • コード補間
    • auto-complete
    • company
  • エラーチェック
    • flymake
    • flycheck
  • リファクタリング
    • emacs-refactor
  • インタープリタ・デバッカ
    • emacs-dbgr
  • プロジェクト管理
    • projectile
  • ドキュメント参照
    • eldoc

最近, 以下の記事を見つけたので, 刺激をうけてまとめた.

Eclipse よりも Emacs が好き

かつて, Eclipse に洗脳されていた若き日の自分は, Eclipse における C/C++ の開発環境を徹底的に調べた.

Emacs と Eclipse どちらが優れているか?

機能的には, 優劣つけがたい. あとは好き嫌いだと思う.

  • ゴテゴテの Eclipse の UI が嫌い
  • Emacs のテキスト操作における圧倒的優位性

を考慮すると, 今は Emacs のほうが好きだ.

ただ, Emacs は 以下に書くように 設定が大変 なので,

  • 導入が面倒なひと
  • 初心者
  • サラリーマン

は Eclipse CDT でよいのでは??

実際の設定

github の dotfiles のリンクをはっておきます.

major-mode

C 言語・ C++ のためのモード.

cc-mode

C, C++, Objc, Java などなどをいっぺんに設定するモード

マニュアル.

c-mode-common-hook は java にも適用されてしまうようだ.

(require 'cc-mode)

;; c-mode-common-hook は C/C++ の設定
(add-hook 'c-mode-common-hook
          (lambda ()
            (setq c-default-style "k&r") ;; カーニハン・リッチースタイル
            (setq indent-tabs-mode nil)  ;; タブは利用しない
            (setq c-basic-offset 2)      ;; indent は 2 スペース
            ))

c++-mode

C++ 言語固有設定.

以下の記述でヘッダファイルが c++ として認識される.

(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))

Error Check

今は, flymake よりも, flycheck でしょう.

flycheck

gcc, clnag, cppcheck が default のチェッカーとして用意されている.

参考: 今は自分で定義しなくても build-in されているよう.


(add-hook 'c-mode-common-hook 'flycheck-mode)
  • checker の変更は M-x flycheck-select-checker
  • helm-flycheck で helm i/f から エラーを選択.

gcc

gcc だとなにも検出してくれない.なんでだろう. -> 結果が日本語表示だったから

(defmacro flycheck-define-clike-checker (name command modes)
  `(flycheck-define-checker ,(intern (format "%s" name))
     ,(format "A %s checker using %s" name (car command))
     :command (,@command source-inplace)
     :error-patterns
     ((warning line-start (file-name) ":" line ":" column ": 警告:" (message) line-end)
      (error line-start (file-name) ":" line ":" column ": エラー:" (message) line-end))
     :modes ',modes))
(flycheck-define-clike-checker c-gcc-ja
                   ("gcc" "-fsyntax-only" "-Wall" "-Wextra")
                   c-mode)
(add-to-list 'flycheck-checkers 'c-gcc-ja)
(flycheck-define-clike-checker c++-g++-ja
                   ("g++" "-fsyntax-only" "-Wall" "-Wextra" "-std=c++11")
                   c++-mode)
(add-to-list 'flycheck-checkers 'c++-g++-ja)

Refactoring

semantic-refactoring

Semantic Refactor is a refactoring tool for C/C++.

ついに見つけた, extract method. menu で番号を選択するとバグっているので, Enter で選択.(そのうちなおるかと)

(require 'srefactor)
(define-key c-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)
(define-key c++-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)

Completion

auto-complete-c-headers

ヘッダの情報源

(require 'auto-complete-c-headers)
(add-hook 'c++-mode-hook '(setq ac-sources (append ac-sources '(ac-source-c-headers))))
(add-hook 'c-mode-hook '(setq ac-sources (append ac-sources '(ac-source-c-headers))))

clang-complete-async

clang を利用した 補完. 構造体とかもばっちり!

(require 'auto-complete-clang-async)

(defun ac-cc-mode-setup ()
  (setq ac-clang-complete-executable "~/.emacs.d/el-get/repo/clang-complete-async/clang-complete")
  (setq ac-sources (append ac-sources '(ac-source-clang-async)))
  (ac-clang-launch-completion-process))

(defun my-ac-config ()
  (add-hook 'c-mode-common-hook 'ac-cc-mode-setup)
  (add-hook 'auto-complete-mode-hook 'ac-common-setup)
  (global-auto-complete-mode t))
  (my-ac-config)

function-args

C/C++ 用の 補完. CEDET のモダンな置き換え.

moo-complete で構造体やクラス変数が置換できるのがうれしい.

  • M-o moo-complete semantic な補完
  • M-i fa-show 関数ヒントをポップアップ
  • M-j fa-jump-maybe ポップアップ状態でオスとジャンプ
  • moo-propose-overide オーバーライドを suggest
  • moo-propose-variable 変数を suggest
(require 'function-args)
(fa-config-default)

(define-key function-args-mode-map (kbd "M-o") nil)
(define-key c-mode-map (kbd "C-M-:") 'moo-complete)
(define-key c++-mode-map (kbd "C-M-:") 'moo-complete)

(custom-set-faces
 '(fa-face-hint ((t (:background "#3f3f3f" :foreground "#ffffff"))))
 '(fa-face-hint-bold ((t (:background "#3f3f3f" :weight bold))))
 '(fa-face-semi ((t (:background "#3f3f3f" :foreground "#ffffff" :weight bold))))
 '(fa-face-type ((t (:inherit (quote font-lock-type-face) :background "#3f3f3f"))))
 '(fa-face-type-bold ((t (:inherit (quote font-lock-type-face) :background "#999999" :bold t)))))

rtags

clang をつかった便利機能詰め合わせ.

設定が大変そうだな.. これは今回は挫折.

fixit って, 自動エラー修正? スゴそう.

Document

ggtags

ggtags も c 言語ように eldoc 機能を提供している. ggtags は後述.

c-eldoc

C 言語用 eldoc 機能.

(require 'c-eldoc)
(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode)
(add-hook 'c++-mode-hook 'c-turn-on-eldoc-mode)
(setq c-eldoc-buffer-regenerate-time 60)

Debugger

gdb

M-x gdb 標準搭載.

emacs-dbgr

デバッグ用 統一 I/F M-x realgud:gdb

gdb との違いはよくわからない.

(require 'realgud)

その他

タグジャンプ

ggtags

タグジャンプ用のツール. GNU Global を利用.

(require 'ggtags)
(add-hook 'c-mode-common-hook
          (lambda ()
            (when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'asm-mode)
              (ggtags-mode 1))))

;; use helm
(setq ggtags-completing-read-function nil)

;; use eldoc
(setq-local eldoc-documentation-function #'ggtags-eldoc-function)

;; imenu
(setq-local imenu-create-index-function #'ggtags-build-imenu-index)

(define-key ggtags-mode-map (kbd "C-c g s") 'ggtags-find-other-symbol)
(define-key ggtags-mode-map (kbd "C-c g h") 'ggtags-view-tag-history)
(define-key ggtags-mode-map (kbd "C-c g r") 'ggtags-find-reference)
(define-key ggtags-mode-map (kbd "C-c g f") 'ggtags-find-file)
(define-key ggtags-mode-map (kbd "C-c g c") 'ggtags-create-tags)
(define-key ggtags-mode-map (kbd "C-c g u") 'ggtags-update-tags)

(define-key ggtags-mode-map (kbd "M-,") 'pop-tag-mark)

helm-gtags

helm I/F を利用した gtags 操作. 自分は ggtags をつかってる.

projectile

プロジェクト管理用の デファクトスタンダード.

自動でプロジェクトのルートディレクトリを探して, それ以下のファイルを見つけたり色々できる.

.projectile ファイルをマニュアルで作成することで, そのフォルダを Route Folder と認識出来る.(要 Emacs 再起動)

(require  'projectile)
(projectile-global-mode)

;; windows indexing 高速化のおまじない.
(setq projectile-indexing-method 'alien)

  ;; 大きいプロジェクトだと劇的に速度が改善するらしい.
(setq projectile-enable-caching t)

GNU Global と組み合わせるには, ggtags が必要.(gtags ではないので注意)

以下で GTAGS を作成.

  • projectile-regenerate-tags
(when (executable-find "gtags")
   (setq projectile-tags-file-name "GTAGS")
   (setq projectile-tags-command "gtags")))

helm-make

C 言語といったら make でしょう. make 用 helm I/F.

(require 'helm-make)

(eval-after-load 'makefile-mode
  '(define-key makefile-mode-map (kbd "M-\"") 'helm-make-projectile))
(define-key c-mode-map (kbd "M-\"") 'helm-make-projectile)
(define-key c++-mode-map (kbd "M-\"") 'helm-make-projectile)

Special Thanks

26 Sep 2014, 12:43

C 言語でシステムコールを利用してファイル操作をしてみる.

はじめに

CIFS プロトコルを勉強している.

CIFS プロトコルは, ファイル読み書きのシステムコールを そのままネットワーク上に流したような仕様になっている.

エクスプローラから見れば, ファイルシステムがリモートにあろうが ローカルにあろうが, 意識することなくファイルにアクセスできる. それは, ファイルアクセスをすると, Windows のカーネル・モードにあるリダイレクタが呼び出されて, 適切なデバイスに対してコマンドを発行してくれるから.

つまり, ファイルアクセスの仕組みを理解すれば, CIFS のプロトコルも理解が深まると言うことだ!

ということで, C 言語で システムコールを利用して ファイルアクセスをしてみた.

つごうにより, 環境は ArchLinux だけど…

ファイル作成

やること

<div class="outline-text-3" id="text-2-1">
  <p>
    /home/tsu-nera/tmp 配下に test というファイルを新規作成する.
  </p>

  <ul class="org-ul">
    <li>
      <a href="https://gist.github.com/tsu-nera/f0be86e0a704471372b3">https://gist.github.com/tsu-nera/f0be86e0a704471372b3</a>
    </li>
  </ul>
</div>

touch で作成する

<div class="outline-text-3" id="text-2-2">
  <p>
    Unix のコマンド touch で作成する.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/Touch_(UNIX)">touch (UNIX) &#8211; Wikipedia</a>
    </li>
  </ul>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221; ]<br /> touch /home/tsu-nera/tmp/test<br /> [/sourcecode]
  </p>
</div>

<div id="outline-container-sec-2-2-1" class="outline-4">
  <h4 id="sec-2-2-1">
    touch のソースを眺める
  </h4>

  <div class="outline-text-4" id="text-2-2-1">
    <p>
      GNU coreutils のソースを眺める.
    </p>

    <ul class="org-ul">
      <li>
        <a href="https://github.com/goj/coreutils/blob/master/src/touch.c">https://github.com/goj/coreutils/blob/master/src/touch.c</a>
      </li>
    </ul>

    <p>
      そして,fd_reopen という関数の中で open/close が利用されている. <a href="https://github.com/goj/coreutils/blob/master/lib/fd-reopen.c">https://github.com/goj/coreutils/blob/master/lib/fd-reopen.c</a>
    </p>
  </div>
</div>

<div id="outline-container-sec-2-2-2" class="outline-4">
  <h4 id="sec-2-2-2">
    strace でみてみる
  </h4>

  <div class="outline-text-4" id="text-2-2-2">
    <p>
      プログラムが使用するシステムコールおよび受け取るシグナルを監視するツール.
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://ja.wikipedia.org/wiki/Strace">strace &#8211; Wikipedia</a>
      </li>
    </ul>

    <p>
      [sourcecode language=&#8221;text&#8221; title=&#8221;&#8221; ]<br /> strace touch /home/tsu-nera/tmp/test<br /> [/sourcecode]
    </p>

    <p>
      こうなった.
    </p>

    <p>
      [sourcecode language=&#8221;text&#8221; title=&#8221;&#8221; ]<br /> execve (&#8220;/usr/bin/touch&#8221;, [&#8220;touch&#8221;, &#8220;/home/tsu-nera/tmp/test&#8221;], [/* 50 vars */]) = 0<br /> brk (0) = 0x6ce000<br /> access (&#8220;/etc/ld.so.preload&#8221;, R_OK) = -1 ENOENT (No such file or directory)<br /> open (&#8220;/usr/local/lib/tls/x86_64/libc.so.6&#8221;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)<br /> stat (&#8220;/usr/local/lib/tls/x86_64&#8221;, 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory)<br /> open (&#8220;/usr/local/lib/tls/libc.so.6&#8221;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)<br /> stat (&#8220;/usr/local/lib/tls&#8221;, 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory)<br /> open (&#8220;/usr/local/lib/x86_64/libc.so.6&#8221;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)<br /> stat (&#8220;/usr/local/lib/x86_64&#8221;, 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory)<br /> open (&#8220;/usr/local/lib/libc.so.6&#8221;, O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)<br /> stat (&#8220;/usr/local/lib&#8221;, {st_mode=S_IFDIR|0755, st_size=4096, &#8230;}) = 0<br /> open (&#8220;/etc/ld.so.cache&#8221;, O_RDONLY|O_CLOEXEC) = 4<br /> fstat (4, {st_mode=S_IFREG|0644, st_size=166490, &#8230;}) = 0<br /> mmap (NULL, 166490, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f042abdd000<br /> close (4) = 0<br /> open (&#8220;/usr/lib/libc.so.6&#8221;, O_RDONLY|O_CLOEXEC) = 4<br /> read (4, &#8220;\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\1\2\0\0\0\0\0&#8243;&#8230;, 832) = 832<br /> fstat (4, {st_mode=S_IFREG|0755, st_size=1984416, &#8230;}) = 0<br /> mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abdc000<br /> mmap (NULL, 3813200, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f042a642000<br /> mprotect (0x7f042a7db000, 2097152, PROT_NONE) = 0<br /> mmap (0x7f042a9db000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x199000) = 0x7f042a9db000<br /> mmap (0x7f042a9e1000, 16208, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f042a9e1000<br /> close (4) = 0<br /> mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abdb000<br /> mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abda000<br /> arch_prctl (ARCH_SET_FS, 0x7f042abdb700) = 0<br /> mprotect (0x7f042a9db000, 16384, PROT_READ) = 0<br /> mprotect (0x60d000, 4096, PROT_READ) = 0<br /> mprotect (0x7f042ac06000, 4096, PROT_READ) = 0<br /> munmap (0x7f042abdd000, 166490) = 0<br /> brk (0) = 0x6ce000<br /> brk (0x6ef000) = 0x6ef000<br /> open (&#8220;/usr/lib/locale/locale-archive&#8221;, O_RDONLY|O_CLOEXEC) = 4<br /> fstat (4, {st_mode=S_IFREG|0644, st_size=2581856, &#8230;}) = 0<br /> mmap (NULL, 2581856, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f042a3cb000<br /> close (4) = 0<br /> open (&#8220;/home/tsu-nera/tmp/test&#8221;, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 4<br /> dup2 (4, 0) = 0<br /> close (4) = 0<br /> utimensat (0, NULL, NULL, 0) = 0<br /> close (0) = 0<br /> close (1) = 0<br /> close (2) = 0<br /> exit_group (0) = ?<br /> +++ exited with 0 +++<br /> [/sourcecode]
    </p>

    <p>
      見にくいので, 統計情報を出力する.
    </p>

    <p>
      あるディレクトリ配下にファイルを作成すだけでも, 結構な数のシステムコールが呼ばれていることが分かる.
    </p>

    <p>
      [sourcecode language=&#8221;text&#8221; title=&#8221;&#8221; ]<br /> [tsu-nera]% strace -c touch /home/tsu-nera/tmp/test<br /> % time seconds usecs/call calls errors syscall<br /> &#8212;&#8212; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;-<br /> 0.00 0.000000 0 1 read<br /> 0.00 0.000000 0 8 4 open<br /> 0.00 0.000000 0 7 close<br /> 0.00 0.000000 0 4 3 stat<br /> 0.00 0.000000 0 3 fstat<br /> 0.00 0.000000 0 8 mmap<br /> 0.00 0.000000 0 4 mprotect<br /> 0.00 0.000000 0 1 munmap<br /> 0.00 0.000000 0 3 brk<br /> 0.00 0.000000 0 1 1 access<br /> 0.00 0.000000 0 1 dup2<br /> 0.00 0.000000 0 1 execve<br /> 0.00 0.000000 0 1 arch_prctl<br /> 0.00 0.000000 0 1 utimensat<br /> &#8212;&#8212; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;-<br /> 100.00 0.000000 44 8 total<br /> [/sourcecode]
    </p>
  </div>
</div>

C 言語 ライブラリで実装してみる

<div class="outline-text-3" id="text-2-3">
  <p>
    C 言語で ファイル操作を行うために, fopen, fclose を利用する.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/fopen.3.html">Man page of FOPEN</a>
    </li>
    <li>
      <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/fclose.3.html">Man page of FCLOSE</a>
    </li>
  </ul>

  <p>
    [sourcecode language=&#8221;c&#8221; title=&#8221;&#8221; ]<br /> #include <stdio.h><br /> int main (void)<br /> {<br /> FILE *fp;<br /> fp = fopen (&#8220;/home/tsu-nera/tmp/test&#8221;, &#8220;w&#8221;);<br /> fclose (fp);<br /> return 0;<br /> }<br /> [/sourcecode] </div> </div> 

    <div id="outline-container-sec-2-4" class="outline-3">
      <h3 id="sec-2-4">
        C 言語 システムコールで実装してみる
      </h3>

      <div class="outline-text-3" id="text-2-4">
        <p>
          では, 本題. opne/close を利用する.
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/open.2.html">Man page of OPEN</a>
          </li>
          <li>
            <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/close.2.html">Man page of CLOSE</a>
          </li>
        </ul>

        <p>
          fopen と open の違いはここがわかりやすかった.
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://d.hatena.ne.jp/skyjoker/20130102/1357093289">fopen (高水準入出力) と open (低水準入出力) の違い &#8211; skyjoker (飛びます)</a>
          </li>
        </ul>

        <p>
          [sourcecode language=&#8221;c&#8221; title=&#8221;&#8221; ]<br /> #include <sys/types.h><br /> #include <sys/stat.h><br /> #include <fcntl.h><br /> #include <unistd.h>
        </p>

        <p>
          int main (void)<br /> {<br /> int fd;<br /> fd = open (&#8220;/home/tsu-nera/tmp/test&#8221;, O_RDWR|O_CREAT, S_IREAD | S_IWRITE);<br /> close (fd);<br /> return 0;<br /> }<br /> [/sourcecode]
        </p>
      </div>
    </div></div> 

    <div id="outline-container-sec-3" class="outline-2">
      <h2 id="sec-3">
        ファイル書き込み
      </h2>

      <div class="outline-text-2" id="text-3">
        <p>
          ファイル新規作成を応用して, ファイルにデータを書き込んでみる.
        </p>
      </div>

      <div id="outline-container-sec-3-1" class="outline-3">
        <h3 id="sec-3-1">
          やること
        </h3>

        <div class="outline-text-3" id="text-3-1">
          <p>
            /home/tsu-nera/tmp 配下に test という 1MB の ファイルを新規作成する.
          </p>
        </div>
      </div>

      <div id="outline-container-sec-3-2" class="outline-3">
        <h3 id="sec-3-2">
          dd でやってみる
        </h3>

        <div class="outline-text-3" id="text-3-2">
          <p>
            Unix コマンドの dd を利用して, 1MB のファイルを作成する.
          </p>

          <p>
            [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221; ]<br /> dd if=/dev/urandom of=/home/tsu-nera/tmp/test count=1024 bs=1024<br /> [/sourcecode]
          </p>
        </div>

        <div id="outline-container-sec-3-2-1" class="outline-4">
          <h4 id="sec-3-2-1">
            dd コマンドのソースをながめる
          </h4>

          <div class="outline-text-4" id="text-3-2-1">
            <p>
              GNU coreutils のソースを眺める.
            </p>

            <ul class="org-ul">
              <li>
                <a href="https://github.com/goj/coreutils/blob/master/src/dd.c">https://github.com/goj/coreutils/blob/master/src/dd.c</a>
              </li>
            </ul>

            <p>
              たとえば以下のように write 関数が利用されている.
            </p>

            <p>
              [sourcecode language=&#8221;c&#8221; title=&#8221;&#8221; ]<br /> while (total_written < size) { ssize_t nwritten; process_signals (); nwritten = write (fd, buf + total_written, size - total_written); if (nwritten < 0) { if (errno != EINTR) break; } else if (nwritten == 0) { /* Some buggy drivers return 0 when one tries to write beyond a device's end. (Example: Linux kernel 1.2.13 on /dev/fd0.) Set errno to ENOSPC so they get a sensible diagnostic. */ errno = ENOSPC; break; } else total_written += nwritten; } [/sourcecode] </div> </div> </div> 

              <div id="outline-container-sec-3-3" class="outline-3">
                <h3 id="sec-3-3">
                  C 言語 ライブラリで実装してみる
                </h3>

                <div class="outline-text-3" id="text-3-3">
                  <p>
                    fwrite 関数で書き込む.
                  </p>

                  <ul class="org-ul">
                    <li>
                      <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/fwrite.3.html">Man page of FREAD</a>
                    </li>
                  </ul>

                  <p>
                    [sourcecode language=&#8221;c&#8221; title=&#8221;&#8221; ]<br /> #include <stdio.h><br /> #include <stdlib.h>
                  </p>

                  <p>
                    #define WRITE_SIZE 1024<br /> #define WRITE_COUNT 1024
                  </p>

                  <p>
                    int main (void)<br /> {<br /> int i;<br /> char r[WRITE_SIZE];<br /> FILE *fp;
                  </p>

                  <p>
                    // generate random value<br /> for (i = 0; i < WRITE_SIZE; i++) { r[i] = rand (); } // open fp = fopen ("/home/tsu-nera/tmp/test", "w"); // write for (i = 0; i < WRITE_COUNT; i++) { fwrite (r, sizeof (char), WRITE_SIZE, fp); } // close fclose (fp); return 0; } [/sourcecode] </div> </div> 

                    <div id="outline-container-sec-3-4" class="outline-3">
                      <h3 id="sec-3-4">
                        C 言語 システムコールで実装してみる
                      </h3>

                      <div class="outline-text-3" id="text-3-4">
                        <p>
                          write 関数で書き込む.
                        </p>

                        <ul class="org-ul">
                          <li>
                            <a href="http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/write.2.html">Man page of WRITE</a>
                          </li>
                        </ul>

                        <p>
                          [sourcecode language=&#8221;c&#8221; title=&#8221;&#8221; ]<br /> #include <sys/types.h><br /> #include <sys/stat.h><br /> #include <fcntl.h><br /> #include <unistd.h><br /> #include <stdlib.h>
                        </p>

                        <p>
                          #define WRITE_SIZE 1024<br /> #define WRITE_COUNT 1024
                        </p>

                        <p>
                          int main (void)<br /> {<br /> int i;<br /> int fd;<br /> char r[WRITE_SIZE];
                        </p>

                        <p>
                          // generate random value<br /> for (i = 0; i < WRITE_SIZE; i++) { r[i] = rand (); } // open fd = open ("/home/tsu-nera/tmp/test", O_RDWR|O_CREAT, S_IREAD|S_IWRITE); // write for (i = 0; i < WRITE_COUNT; i++) { write (fd, r, WRITE_SIZE); } // close close (fd); return 0; } [/sourcecode] </div> </div> </div> 

                          <div id="outline-container-sec-4" class="outline-2">
                            <h2 id="sec-4">
                              Special Thanks
                            </h2>

                            <div class="outline-text-2" id="text-4">
                              <ul class="org-ul">
                                <li>
                                  <a href="http://www.atmarkit.co.jp/ait/articles/1111/16/news161.html">知ってトクするシステムコール (1):システムコールについてどれくらいご存じですか? (1/2) &#8211; @ IT</a>
                                </li>
                                <li>
                                  <a href="http://linuxc.info/file/file1/">LinuxC | ファイルのオープン, クローズ</a>
                                </li>
                                <li>
                                  <a href="http://curtaincall.weblike.jp/portfolio-unix/api.html">システムコールを理解する | UNIX world</a>
                                </li>
                              </ul>
                            </div>
                          </div>

10 May 2014, 23:16

[edX]Embedded Systems – Shape The World ずっと受けたかった組み込みソフト開発の授業

はじめに

レジスタも触ったことのないニセエセ組込みエンジニアなので、 リアル組込みエンジニアになりたくて、edXで組込み開発の学習をしました。

結果は、途中で挫折しました。全15週の10週目くらいで挫折。 なので、この記事も中途半端な記事になります。

自分はリアル組み込みエンジニアにはなれませんでしたorz.

[toc]

内容

0,1のフリップフロップから電子回路、レジスタへと、基礎からしっかり解説される。 オームの法則とか、忘れた。電子回路は読んで読まないふりをした。

期待していた?電子回路の知識は十分過ぎるほど出てきた。 ADC,DACあたりはほんとうに挫折。

言語はC言語

<div class="outline-text-3" id="text-2-1">
  <p>
    言語はもちろん、C言語だ。補足的にアセンブラ言語もでてくる。楽勝楽勝。
  </p></p>
</div></p>

実践も重視

<div class="outline-text-3" id="text-2-2">
  <p>
    知識的な部分だけではなく、開発プロセスや品質の考え方、デバッグ手法など 実践的な部分も説明される。
  </p>

  <p>
    開発プロセスでは、フローチャートやサブルーチンといった、 手続き型用語が解説されて、やや時代遅れを感じた。
  </p></p>
</div></p>

進め方

講義の流れ

<div class="outline-text-3" id="text-3-1">
  <p>
    イントロダクションとして、2人のコント?から始まる。 動画よりも、文章の方が多め。
  </p>

  <p>
    動画ではとくにパワーポイントは使わずにホワイトボードで解説されるので、 字がきれいでなく読みにくい。
  </p></p>
</div></p>

Labについて

<div class="outline-text-3" id="text-3-2">
  <p>
    講義よりも比重が置かれているのが、Labと呼ばれている実機学習。
  </p>

  <p>
    毎週課題が出されて、それに取り組むことで講義の内容の理解を深める。
  </p>

  <p>
    課題の評価はテストコードで自動でチェックされる。 シミュレータと実機の両方で評価することが求められる。
  </p>

  <p>
    評価ボードは、Texas Instrumentsの EK-LM4F120XLというものを買った。 ネットで注文して購入する必要がある。ARMの Cortex-Mが載っている。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.tij.co.jp/tool/jp/ek-lm4f120xl">Stellaris LM4F120 LaunchPad 評価ボード &#8211; EK-LM4F120XL &#8211; TI ツール・フォルダ</a>
    </li>
  </ul>

  <p>
    開発環境としては、Keil uVision for the ARM, MDK-Lite (32KB) Editionを利用する。 ARMの開発をするためのIDE.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.keil.com/uvision/default.asp">µVision IDE &#8211; Overview</a>
    </li>
  </ul>
</div>

<div id="outline-container-sec-3-2-1" class="outline-4">
  <h4 id="sec-3-2-1">
    Lチカ
  </h4>

  <div class="outline-text-4" id="text-3-2-1">
    <iframe width="560" height="315" src="//www.youtube.com/embed/32fij3U6SUo" frameborder="0" allowfullscreen></iframe>
  </div></p>
</div></p>

感想

自己紹介

<div class="outline-text-3" id="text-4-1">
  <p>
    まず、なぜ私がニセエセ組込みエンジニアなのかを説明したい。 そのために、まずは自分のしていた仕事を書こうと思う。 このブログに仕事の話を書くのも初めてな気がする。
  </p>

  <p>
    今は別のこと(社内ニートとも)をしているけれども、ちょっと前までは、 ストレージ装置の組込みソフトエンジニアだった。
  </p>

  <p>
    開発はそこそこ大規模で、機能モジュールごとに担当チームが別れている。
  </p>

  <p>
    自分の所属していたチームは、エラー発生時のリカバリが担当。 つまり、装置でエラーが発生したときに、 可用性を失わないためにあらゆる手段をつかってあれこれする役目。
  </p>

  <p>
    そのなかでも、自分が担当していた部分は、 ハードエラーが発生して装置内の各種ドライバから通知を受けたときに、 装置の可用性を失わないためはどうすればいいかを一生懸命考える部分。
  </p>

  <div class="figure">
    <p>
      <img src="http://futurismo.biz/wp-content/uploads/wpid-sample5.png" alt="sample.png" />
    </p></p>
  </div>

  <p>
    ハードと接するinterfaceはドライバ層で隠蔽されているため、 実は自分はレジスタを触ったことがない!
  </p>

  <p>
    そもそもレジスタがなんだかわからない。 雑誌『Interface』や『トランジスタ技術』が 会社の休憩ゾーンにおいてあるが、書いてあることがほぼわからない。
  </p>

  <p>
    これって、組込みエンジニアとしてどうなの? これが、ニセエセ組込みエンジニアたる所以である。
  </p></p>
</div></p>

課題

<div class="outline-text-3" id="text-4-2">
  <p>
    自分は、組込みエンジニアという肩書きではあるものの、 実際はハードウェアを理解していない。
  </p>

  <p>
    以下の記事にとても共感する。
  </p>

  <p>
    <a href="http://monoist.atmarkit.co.jp/mn/articles/0703/26/news101.html">組み込みギョーカイの常識・非常識(8):組み込みソフトウェアって何</a>
  </p>

  <p>
    ちなみに、この記事を書いた著者のことを調べてみるとこんな本を書いてた。
  </p>

  <div class='amazlink-box' style='text-align:left;padding-bottom:20px;font-size:small;/zoom: 1;overflow: hidden;'>
    <div class='amazlink-list' style='clear: both;'>
      <div class='amazlink-image' style='float:left;margin:0px 12px 1px 0px;'>
        <a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' target='_blank' rel='nofollow'><img src='http://ecx.images-amazon.com/images/I/41MIz39174L._SL160_.jpg' style='border: none;' /></a>
      </div>

      <div class='amazlink-info' style='height:160; margin-bottom: 10px'>
        <div class='amazlink-name' style='margin-bottom:10px;line-height:120%'>
          <a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' rel='nofollow' target='_blank'>組込みソフトウェアエンジニアのためのハードウェア入門 (組込みプレスSelection)</a>
        </div>

        <div class='amazlink-powered' style='font-size:80%;margin-top:5px;line-height:120%'>
          posted with <a href='http://amazlink.keizoku.com/' title='アマゾンアフィリエイトリンク作成ツール' target='_blank'>amazlink</a> at 14.05.11
        </div>

        <div class='amazlink-detail'>
          みわ よしこ
        </div>

        <div class='amazlink-sub-info' style='float: left;'>
          <div class='amazlink-link' style='margin-top: 5px'>
            <img src='http://amazlink.fuyu.gs/icon_amazon.png' width='18' /><a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' rel='nofollow' target='_blank'>Amazon</a> <img src='http://amazlink.fuyu.gs/icon_rakuten.gif' width='18' /><a href='http://hb.afl.rakuten.co.jp/hgc/g00q0724.n763w947.g00q0724.n763x2b4/archives/c=http%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F6186429%2F&#038;m=http%3A%2F%2Fm.rakuten.co.jp%2Frms%2Fmsv%2FItem%3Fn%3D6186429%26surl%3Dbook' rel='nofollow' target='_blank'>楽天</a>
          </div>
        </div>
      </div>
    </div>
  </div>

  <p>
    ハードウェアの担当者と一緒の打ち合わせに参加しても、正直ちんぷんかんぷん。
  </p>

  <p>
    ということで、以下が学習目標。
  </p></p>
</div></p>

学習目標

<div class="outline-text-3" id="text-4-3">
  <p>
    DMA Driver が DMA Portのハードエラーを検出して、 そのエラー要因ごとに異常を通知する仕組みを理解すること。
  </p>

  <p>
    DriverがDMAなのは、 仕事で一番お世話になったのが DMA Driverの担当の人だったから。
  </p>

  <p>
    ここからは、勉強メモ。
  </p></p>
</div></p>

Embeded System

組み込みシステム。

特定の機能を実現するために機械や機器に組み込まれるコンピュータシステム。

組み込みシステムの主な構成要素は以下。

  • Embedded Systems
    • MicroCotroller
      • Memory
        • RAM
        • ROM
      • Processor(CPU)
      • I/O Ports
      • DAC
      • Bas
      • Timer
    • External Circuits
    • Physical Device
      • Sensor
      • ADC

以下のような特徴をもつ。

  • A microcontroller hidden inside
  • A dedicated purpose
  • Run in real time
  • Input/output is important
  • High volume, low cost
  • Extremely reliable
  • Low power
  • Small size and weight

MicroController

マイクロコントローラー。いわゆる、マイコン。

Microcontrollers, which are microcomputers incorporating the processor,
RAM, ROM and I/O ports into a single package,
are often employed in an embedded system because of their low cost,
small size, and low power requirements.

I/O Port

<div class="outline-text-3" id="text-6-1">
  <p>
    Input Port/Output Portの略。 Input Portは 外部の世界(外部の集積回路、sensor, etc) からの情報をコンピュータのなかに入れる。Output Portはその逆。
  </p>

  <p>
    A port is a physical connection between the computer and its outside world.
  </p></p>
</div>

<div id="outline-container-sec-6-1-1" class="outline-4">
  <h4 id="sec-6-1-1">
    device driver
  </h4>

  <div class="outline-text-4" id="text-6-1-1">
    <p>
      a set of software functions that facilitate the use of an I/O port.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-6-1-2" class="outline-4">
  <h4 id="sec-6-1-2">
    GPIO
  </h4>

  <div class="outline-text-4" id="text-6-1-2">
    <p>
      GPIOはGeneral Purpose Input/Output(汎用入出力)の略語。
    </p>

    <p>
      <a href="http://ja.wikipedia.org/wiki/GPIO">GPIO &#8211; Wikipedia</a>
    </p>

    <p>
      LSIチップや電子機器の備える入出力端子の一種で、 設定次第で様々な用途に利用できるもの。
    </p>

    <p>
      ソフトウェアの指示によって任意の入力あるいは出力に利用することができる。 複数の端子がGPIOに割り当てられている場合には、 これを一つのグループとして一括して制御することができ「GPIOポート」などと呼ばれる
    </p>

    <p>
      <a href="http://e-words.jp/w/GPIO.html">GPIOとは 【 General Purpose Input/Output 】 &#8211; 意味/解説/説明/定義 : IT用語辞典</a>
    </p>

    <p>
      PinはGPIOの構成要素。たとえば、GPIO PortAは、PA0-PA7の8つのPinからできている。
    </p>

    <p>
      Pins can be configured for digital I/O, analog input, timer I/O, or serial I/O. For example PA0 can be digital I/O or serial input.
    </p>

    <p>
      Pinのそれぞれが外部デバイスに接続される。 用途は、レジスタの設定によって自由にできる。
    </p>

    <ul class="org-ul">
      <li>
        PA1 &#x2026; LEDへのOutput用
      </li>
      <li>
        PA2 &#x2026; Switch からの Input用
      </li>
      <li>
        PA3 &#x2026; UART の Input用
      </li>
      <li>
        PA4 &#x2026; UART の Output用
      </li>
    </ul>
  </div></p>
</div></p>

Register

<div class="outline-text-3" id="text-6-2">
  <p>
    コンピュータのプロセッサなどが内蔵する記憶回路で、 制御装置や演算装置や実行ユニットに直結した、 操作に要する速度が最速の、比較的少量のものを指す。
  </p>

  <p>
    一般に、論理回路において、フリップフロップなどにより状態を保持する装置をレジスタと呼ぶ。 コンピュータにおいては、プロセッサが内蔵しているそれを指す。 プロセッサには、プログラムが読み書きできるレジスタ以外に、 プロセッサ自身が動作するためのレジスタがあり、内部レジスタなどと呼ばれる。
  </p>

  <p>
    <a href="http://ja.wikipedia.org/wiki/%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)">レジスタ (コンピュータ) &#8211; Wikipedia</a>
  </p>

  <p>
    Registers are high-speed storage inside the processor.
  </p></p>
</div>

<div id="outline-container-sec-6-2-1" class="outline-4">
  <h4 id="sec-6-2-1">
    Registerのプログラムでの扱い
  </h4>

  <div class="outline-text-4" id="text-6-2-1">
    <p>
      Pinを操作するためのレジスタには、 アドレス空間の決められたアドレスが割り振られている。(仕様)
    </p>

    <p>
      プログラムでは、あらかじめDefineを利用してレジスタのアドレスを宣言するのが王道。 volatileをつけることで、コンパイラが最適化してアドレスを変更するのを防ぐ。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">#define PA5   (*((volatile unsigned long *)0x40004080))

    <p>
      これは以下と同値。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">data = (*((volatile unsigned long *)0x40004080));

data = 0x40004080; data = (*0x40004080);

    <p>
      そうすると、以下のようにして Registerの値を Read/Writeできる。
    </p>

    <div class="org-src-container">
      <pre class="src src-language"># Register Write

PA5 = 0x20;

Register Read

data = PA5;

    <p>
      初期設定はこんな感じ。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">void PortF_Init(void){ volatile unsigned long delay;

SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0 GPIO_PORTF_CR_R |= 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R &= 0x00; // 3) disable analog function GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL GPIO_PORTF_DIR_R &= ~0x11; // 5.1) PF4,PF0 input, GPIO_PORTF_DIR_R |= 0x08; // 5.2) PF3 output GPIO_PORTF_AFSEL_R &= 0x00; // 6) no alternate function GPIO_PORTF_PUR_R |= 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R |= 0x1F; // 7) enable digital pins PF4-PF0
}

<div id="outline-container-sec-6-2-2" class="outline-4">
  <h4 id="sec-6-2-2">
    LチカExample抜粋
  </h4>

  <div class="outline-text-4" id="text-6-2-2">
    <div class="org-src-container">
      <pre class="src src-language">// symbolic names instead of addresses

#define GPIO_PORTF_DATA_R (*((volatile unsigned long )0x400253FC)) #define GPIO_PORTF_DIR_R (((volatile unsigned long )0x40025400)) #define GPIO_PORTF_AFSEL_R (((volatile unsigned long )0x40025420)) #define GPIO_PORTF_PUR_R (((volatile unsigned long )0x40025510)) #define GPIO_PORTF_DEN_R (((volatile unsigned long )0x4002551C)) #define GPIO_PORTF_LOCK_R (((volatile unsigned long )0x40025520)) #define GPIO_PORTF_CR_R (((volatile unsigned long )0x40025524)) #define GPIO_PORTF_AMSEL_R (((volatile unsigned long )0x40025528)) #define GPIO_PORTF_PCTL_R (((volatile unsigned long )0x4002552C)) #define SYSCTL_RCGC2_R (((volatile unsigned long *)0x400FE108))

// 2. Declarations Section // Global Variables unsigned long SW1; // input from PF4 unsigned long SW2; // input from PF0

// Subroutine to initialize port F pins for input and output // PF4 is input SW1 and PF2 is output Blue LED void PortF_Init(void){ volatile unsigned long delay; SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0 GPIO_PORTF_CR_R |= 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R &= 0x00; // 3) disable analog function GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL GPIO_PORTF_DIR_R &= ~0x11; // 5.1) PF4,PF0 input, GPIO_PORTF_DIR_R |= 0x08; // 5.2) PF3 output GPIO_PORTF_AFSEL_R &= 0x00; // 6) no alternate function GPIO_PORTF_PUR_R |= 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R |= 0x1F; // 7) enable digital pins PF4-PF0
}

void FlashSOS(void){ //S GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); //O GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); //S GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); delay(10); // Delay for 5 secs in between flashes }

Memory

ROM

<div class="outline-text-3" id="text-7-1">
  <p>
    書き込んだデータは消去できないが、電源を切ってもデータが消えない読み出し専用のメモリ.
  </p></p>
</div></p>

RAM

<div class="outline-text-3" id="text-7-2">
  <p>
    データの読み書きは自由に行えるが、電源を切ると内容が消えるメモリ(Random Access Memory)
  </p></p>
</div></p>

Interface

ハードウェアとソフトウェアを結ぶもの。ここでいうところは、ハードウェアインタフェース。

interface is defined as the hardware and software that combine to allow the computer to communicate with the external hardware.

I/O Port, 外部電子回路、物理的デバイス、ソフトウェアなどを集めたもの。

An interface is defined as the collection of the I/O port, external electronics, physical devices, and the software, which combine to allow the computer to communicate with the external world.

以下の4つに分類される。

Parallel Interface

<div class="outline-text-3" id="text-8-1">
  <p>
    パラレルポートとは、コンピュータシステム内で、 ばらばらの周辺機器をケーブルで接続するために使われる物理的なインタフェースの一種。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%83%91%E3%83%A9%E3%83%AC%E3%83%AB%E3%83%9D%E3%83%BC%E3%83%88">パラレルポート &#8211; Wikipedia</a>
    </li>
    <li>
      <a href="http://www.sophia-it.com/content/%E3%83%91%E3%83%A9%E3%83%AC%E3%83%AB%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9">パラレルインターフェースとは 「パラレルインタフェース」 (parallel interface): &#8211; IT用語辞典バイナリ</a>
    </li>
  </ul>
</div></p>

Syncronization

<div class="outline-text-3" id="text-8-2">
  <p>
    ハードウェアとソフトウェアの同期処理。
  </p>

  <p>
    ハードウェアのスピードとソフトウェアのスピードは、 ソフトウェアの方が早いため相互でやりとりするためには以下の手段がある。
  </p></p>
</div>

<div id="outline-container-sec-8-2-1" class="outline-4">
  <h4 id="sec-8-2-1">
    Blind-Cycle
  </h4>

  <div class="outline-text-4" id="text-8-2-1">
    <p>
      決められた時間SleepしたあとにI/Oステータスをチェックする.
    </p>

    <p>
      the software writes data to the output device, triggers (starts) the device, then waits a specified time. We call this method blind, because there is no status information about the I/O device reported to the software.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-2" class="outline-4">
  <h4 id="sec-8-2-2">
    Busy-Wait
  </h4>

  <div class="outline-text-4" id="text-8-2-2">
    <p>
      Input deviceのデータが更新されたときにI/Oステータスをチェックする。
    </p>

    <p>
      状態がBusyならばWait(loop), Readyならば次のステップへ。
    </p>

    <p>
      Busy Wait is a software loop that checks the I/O status waiting for the done state. For an input device, the software waits until the input device has new data, and then reads it from the input device,
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-3" class="outline-4">
  <h4 id="sec-8-2-3">
    Interrupt
  </h4>

  <div class="outline-text-4" id="text-8-2-3">
    <p>
      ハードウェアが発生させる特別な通知。
    </p>

    <p>
      An interrupt uses hardware to cause special software execution. With an input device, the hardware will request an interrupt when input device has new data. The software interrupt service will read from the input device and save in global RAM,
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-4" class="outline-4">
  <h4 id="sec-8-2-4">
    Periodic Polling
  </h4>

  <div class="outline-text-4" id="text-8-2-4">
    <p>
      クロックタイマの割り込み契機でI/Oのステータスをチェック
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-5" class="outline-4">
  <h4 id="sec-8-2-5">
    DMA
  </h4>

  <div class="outline-text-4" id="text-8-2-5">
    <p>
      Direct Memory Access あるメモリから別のメモリに直接情報を書き込む
    </p></p>
  </div></p>
</div></p>

Serial Interface

<div class="outline-text-3" id="text-8-3">
</div>

<div id="outline-container-sec-8-3-1" class="outline-4">
  <h4 id="sec-8-3-1">
    UART
  </h4>

  <div class="outline-text-4" id="text-8-3-1">
    <p>
      Universal Asynchronous Receiver/Transmitter (UART). 調歩同期方式によるシリアル通信をするための汎用I/F。
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://ja.wikipedia.org/wiki/UART">UART &#8211; Wikipedia</a>
      </li>
    </ul>

    <p>
      有名なので、最近のほとんどのマイコンに搭載されているらしい。
    </p></p>
  </div></p>
</div></p>

Thread/Process/Task

Thread

<div class="outline-text-3" id="text-9-1">
  <p>
    A thread is defined as the path of action of software as it executes.
  </p></p>
</div></p>

Process

<div class="outline-text-3" id="text-9-2">
  <p>
    A process is defined as the action of software as it executes.
  </p>

  <p>
    スレッドとプロセスの違いは、変数のスコープの違い?
  </p>

  <p>
    Threads share access to I/O devices, system resources, and global variables, while processes have separate global variables and system resources. Processes do not share I/O devices.
  </p>

  <p>
    実際は、OSによってバラバラ。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://futurismo.biz/archives/2245">スレッドとタスクの違いについてしらべてみた(C++/Linux) | Futurismo</a>
    </li>
  </ul>
</div></p>

Interrupt

Hardware Interrupt Software Action.

Busy-Waitの制御で待ってられない場合は、Interruptを利用する。

ここからは、一般的な説明ではなくてedXの中だけの定義。

Arm/DisArm

<div class="outline-text-4" id="text-10-0-1">
  <p>
    Armとは、ハードウェアが割り込みをあげることを有効化する。
  </p>

  <p>
    DisArmとは、ハードウェアが割り込みをあげることを無効化する。
  </p></p>
</div></p>

Enable/Disable

<div class="outline-text-4" id="text-10-0-2">
  <p>
    Enableは一時的に割り込みを有効化する。
  </p>

  <p>
    Disbleは一時的に割り込みを無効化する。
  </p>

  <p>
    Disable中に発生したInterupptは Pendingされて、Enable時に通知される。
  </p></p>
</div></p>

Interruputの初期化処理

<div class="outline-text-4" id="text-10-0-3">
  <ol class="org-ol">
    <li>
      Trigger flag set by hardware
    </li>
    <li>
      the device is armed by software
    </li>
    <li>
      the device is enabled for interrupts in the NVIC
    </li>
    <li>
      the processor is enabled for interrupts (PRIMASK I bit is clear)
    </li>
    <li>
      the interrupt level must be less than the BASEPRI.
    </li>
  </ol>
</div></p>

Context Switch

<div class="outline-text-4" id="text-10-0-4">
  <p>
    割り込みをハードウェアが検知したときに、 foregroundとbackgroundのスレッドを入れ替える。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81">コンテキストスイッチ &#8211; Wikipedia</a>
    </li>
  </ul>

  <p>
    現在のプロセスの実行を一時停止して、 スタックにレジスタ情報を覚えておく。
  </p>

  <p>
    割り込みハンドラを実行して、 ハンドラの実行が終了したらもとのプロセスを再開する。
  </p>

  <ol class="org-ol">
    <li>
      Current instruction is finished,
    </li>
    <li>
      Eight registers are pushed on the stack,
    </li>
    <li>
      LR is set to 0xFFFFFFF9,
    </li>
    <li>
      IPSR is set to the interrupt number,
    </li>
    <li>
      PC is loaded with the interrupt vector
    </li>
  </ol>
</div></p>

Interrupt Service Routine(ISR)

<div class="outline-text-3" id="text-10-1">
  <p>
    割り込みサービスルーチン。割り込みハンドラともいう。
  </p>

  <p>
    <a href="http://ja.wikipedia.org/wiki/%E5%89%B2%E3%82%8A%E8%BE%BC%E3%81%BF%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9">割り込みハンドラ &#8211; Wikipedia</a>
  </p>

  <p>
    コンテキストスイッチによって、 foregroundで動作している busy-waitなスレッドとISRがスワップされる。
  </p>

  <p>
    割り込み受け付けによって起動されるオペレーティングシステムや デバイスドライバのコールバックルーチン。 割り込みハンドラは割り込み原因によってそれぞれ存在し、 割り込みハンドラがそのタスクを完了するまでにかかる時間も様々である。
  </p></p>
</div>

<div id="outline-container-sec-10-1-1" class="outline-4">
  <h4 id="sec-10-1-1">
    NVIC
  </h4>

  <div class="outline-text-4" id="text-10-1-1">
    <p>
      割り込みハンドラに対応させたい関数は、 startup scriptに事前に登録しておく。
    </p>

    <p>
      vectorというメモリ領域にシステムにどの関数を実行すればいいかをアドレスとして教える。
    </p>

    <p>
      interrupt発生時は vectorを参照して、それに対応する割り込みルーチンの関数を呼ぶ。
    </p>

    <p>
      nested vectored interrupt controller (NVIC) manages interrupts, which are hardware-triggered software functions. Some internal peripherals, like the NVIC communicate directly with the processor via the private peripheral bus (PPB). The tight integration of the processor and interrupt controller provides fast execution of interrupt service routines (ISRs), dramatically reducing the interrupt latency.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-10-1-2" class="outline-4">
  <h4 id="sec-10-1-2">
    Acknowledge
  </h4>

  <div class="outline-text-4" id="text-10-1-2">
    <p>
      割り込みをISRが認識すること。 ISRが割り込みの認識を行った後、同じデバイスからの割り込みが発生しないよう割り込みマスクをする必要がある。 そうしないと、クラッシュする恐れがある。
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://d241445.hosting-sv.jp/community/report/report31.html">レポート31:割り込みサービスルーチン(ISR)の処理</a>
      </li>
    </ul>

    <p>
      実装でやってはいけないことは以下。
    </p>

    <ul class="org-ul">
      <li>
        長時間の処理はしてはいけない。
      </li>
      <li>
        待ち状態になってはいけない、Delay Loopはつかわないほうがよい。
      </li>
      <li>
        呼んではいけない関数がある。
      </li>
    </ul>

    <p>
      割り込みハンドラでは必要最小限の処理のみを行い、別のタスクに通知して、 メインの処理はそっちでさせるように実装すべき。
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-10-1-3" class="outline-4">
  <h4 id="sec-10-1-3">
    ISRからメイン処理への通知方法
  </h4>

  <div class="outline-text-4" id="text-10-1-3">
    <p>
      ISRとメイン処理はグローバルなメモリ領域を介して情報を受渡しする。
    </p>

    <ul class="org-ul">
      <li>
        Binary Semaphore
      </li>
    </ul>

    <p>
      ISRで 決められたflagを立てて、メイン処理でそのフラグを監視する。 flagが1ならば、それのフラグに対応する処理を実施する。
    </p>

    <ul class="org-ul">
      <li>
        MailBox
      </li>
    </ul>

    <p>
      flagとともにデータも渡すこともある。
    </p>

    <p>
      flagをStatusといい、flagとdataを合わせたデータ構造をMailという。 (MailBox Pruducer-Consumer Pattern)
    </p>

    <ul class="org-ul">
      <li>
        FIFO queue
      </li>
    </ul>

    <p>
      ISRでFifoなメモリ領域にデータをPUTし、 メイン処理のloop処理でで定期的にFifoなdataをチェックし、順次実行する。
    </p></p>
  </div></p>
</div></p>

14 Mar 2014, 12:05

C言語の二重インクルード(多重インクルード)防止について

C言語のヘッダファイルでおまじないのように書いているコレ。

#ifndef  _FOO_H_
#define  _FOO_H_

#endif

インクルードガードという。いったいなんなのか調べた。

無限ループ防止

互いのヘッダファイルをインクルードしあうと、コンパイル時に無限ループに陥る。

foo.h

#include "bar.h"

bar.h

#include "foo.h"

実行結果

<div class="outline-text-3" id="text-1-1">
  <div class="org-src-container">
    <pre class="src src-language">  $gcc foo.c bar.c
 ... 
     from foo.h:1,
     from bar.h:4,
     from foo.h:1,
     from bar.h:4,
     from foo.h:1,
     from bar.h:4,
     from foo.h:1,
     from bar.h:4,
     from foo.h:1,
     from bar.h:4,
     from foo.h:1,
     from foo.c:2:

foo.h:1:17: error: #include nested too deeply #include “bar.h”

構造体のコンパイルエラー

一つの.hにある構造体を二つの.cでインクルードすると、コンパイルエラーが発生する仕様。

foo.h

struct test{
  int test;
};

bar.c / foo.c

#include "foo.h"

実行結果

<div class="outline-text-3" id="text-2-1">
  <pre><code>

% gcc bar.c foo.c In file included from bar.c:3:0: foo.h:2:8: error: redefinition of ‘struct test’ struct test{ ^ In file included from bar.h:4:0, from bar.c:2: foo.h:2:8: note: originally defined here struct test{

progma onceについて

インクルードガードを実現するためのコンパイラの仕組みに、#pragma onceというのがある。

ヘッダファイルの先頭に以下を記述するだけ。

#pragma once

#ifndefは別の機能をたまたま応用にしているに過ぎないが、 #pragma onceは機能としてあるので直接的。

Links

07 Dec 2013, 07:45

[Coursera]C++ For C Programmersを受講しました

Cプログラマなので、C++を勉強するために『C++ For C Programmers』を受講しました。

概要

C++の初級的な話題が紹介される。この講義でC++の基礎がマスターできる内容。Cプログラマを対象にしているため、Cとの比較やC++のここがスゴイのだという説明も出てきて、Cしかしらない自分にはこのCについての伏線が嬉しい。

また、なにかにつけてC++11の話題がガッツリ紹介されるので、C++11 For C++98 Programmersというタイトルのほうが実は適切な気がする。

オープニングにJAZZが流れて、ダンディさあふれるのIra Pohl教授が現れる。

[//www.youtube.com/embed/tph2O4qPNMg?rel=0]

話し方がカメみたいにものすごくゆっくりなので、English的な壁は大丈夫だった。スライドにカラーペンで書き込みながら説明されるので、臨場感がある。(しかし字がけっこうきたない)

参考書

参考書は、ネット上にある無料のものと、有料のものがある。



が、自分は利用しなかった。どちらかというと、副読本としては、かつて挫折した独習C++を読んでた。

各回の概要

Week1 C++ as a Better C

A言語からC言語までに至る歴史の説明。そして、C++がC言語に比べてなぜ優れているかを解説する。課題は、C言語でかかれたコードをC++に書きなおす。ここでC++独特の表記をならう。

week2 C++: Basics of Generics and Classes Template

templateが出てくる。より汎用的で、再利用可能な書き方について学ぶ。課題はダイクストラ法の実装。どのへんがC Programmerのためなのだ? モンテカルロ法やPriorityQueueを使いこなす必要があり、難しい。

week3 C++: Class Constructors and Destructors

コンストラクタ、デコンストラクタの説明。または、List構造の説明。Assignmentの実装方法に関するフォローの講義も入る。

week4: C++: Minimum Spanning Tree & Standard Template Library

auto,継承、friend関数などなど。ここで、STLの解説とイテレータという概念が出てくる。だんだんC++ぽくなってくる。Assignmentは最小スパニングツリーをプリム法かクラスカル法で実装。

week5: C++ 11 Standard; Containers, Iterators and Algorithms

主にここではSTLの説明。コンテナ、イテレータ、アルゴリズムの三本柱が詳しく解説される。lambdaの使い方も紹介されるが、理解できなかった。

week6: Hex, the game and C++ Inheritance

後半の大きな話題である、Hex gameの説明が入る。また、重要な概念である、もここで解説。

Module 7: Min-Max and C++11 Classes; Alpha-beta and Polish

Copy Constactor や Move Costractorなど。またHex Gameを実装するための方法が解説される。ミニマックス法やアルファ・ベータ法など。ここで、このCourseのサムネイル画像がチェスの理由を理解した。この先生はチェスがとても好きらしい。チェスにおけるAIの実装方法なども出てくる。

後半の課題である、Hex Gameを 3weekにわたって実装する。この課題で、C++のfeatureを全部注ぎ込みなさいと言われて、けっこう頑張った。

Module 8: Monte Carlo Evaluation; the C++11 Standard

例外処理、スレッド処理などなど、今までで解説していないC++のfeatureももれなく紹介。また、C++中級への道として、簡単なデザインパターンが紹介される。

おわりに

For C Programmerな部分は実はweek1だけだった気がした。グラフ理論やゲーム理論が出てきて、『いったいどのへんがFor C Programmerナンダヨ!』と全生徒が唸ったに違いない。

Cしかできない自分にとっては、まさにうってつけの授業だった。

Hex Game

[//www.youtube.com/embed/kNOFq7aEYUE?rel=0]

05 Nov 2013, 15:39

「モダンC言語プログラミング」を読んだ!C言語の組込みエンジニアのためのモダンテクニックが満載

とてもエキサイティングな本に出会い、一気に読んでしまいました。感想を書こうと思います。



ターゲット読者層は組込み分野!

この本のターゲット読者はズバリ、組込みエンジニア。ソースコードのサンプルも、ズバリ組込みな内容を扱っています。C言語を使う人=組込みの人と決めつけているよう。書籍のあちこちで、このアプローチを組込み開発で適応するためにはどうすればいいかという考察が入るのがよい。

TIOBEというプログラミング言語の統計を見ると、C言語を利用している人がプログラマの2割程度いることがわかる。自分はこのデータを初めて知ったけれども、まずこの事実をしれたことは嬉しい事だ。C言語はいかに重要なのかという論題が冒頭で熱く語られる。

 内容について

各章のテーマは、広く浅く書かれているので、もう少し各章の突っ込んだ内容がほしいところだけれども、それはこの本の趣旨には合わないのだろう。

内容は、自分の日々考えていることに非常にマッチしていて、とてもエキサイティングな読後感でした。以下、自分の過去記事も整理しつつ、各章の覚書。

開発環境について

開発環境である、Ubuntuの導入方法と、Eclipseの使い方が紹介されていた。ここは、得るものはなしかな。

オブジェクト指向

C言語でオブジェクト指向のようにコーディングするためのテクニックが紹介されている。半分知っているようで、知らなかった。C言語でも、オブジェクト指向なプログラミングは可能だと気づかせてくれる。

あとは、Cでオブジェクト指向を勉強するならば、ズバリこの本でしょう。これもオススメ。



デザインパターン

自分の来年の重点学習目標の一つが、デザインパターンをマスターすること。この章は、C言語を利用したデザインパターンの実装方法が紹介されている。この章は知らないことが多く、とても興味深かった。

以下のパターンが紹介されている。

C言語に特化したデザインパターンの本をまだ知らない。これが自分が出会った中で、もっともよくかかれた本かも。この本でも勉強するつもり。まだ読んでない。

いづれにしろ、この章は再読しよう。

TDD リファクタリング

テストフレームワークとして、GoogleTestが紹介される。レガシーコードに対するリファクタリングの実践がサンプルとして載っているのがうれしい。しかも、内容が組込みなので、実践的。パフォーマンスに関する考察もある。

namespaceを利用して、static関数を強引にテストケースに組み込む方法が紹介されていた。C++系のxUnitで利用できるテクニック。

namespace unit_test {
    #include "hogehoge.c"

    TEST(hoge,hogehoge) {
        EXPECT_EQ(3, hoge(1, 2));
    }
}

モックやスタブの定義についての言及は、自分の認識とは違うのだけれども、まあよい。モッキングフレームワークはC言語でいいものがないと書かれていた。そんなことはない、CMockやfffがあるではないか!

CでTDDをするならば、この本が必読本。



継続的インテグレーション

Jenkinsの紹介。これもあまり新しきことはなし。

C言語/C++でJenkins実践入門してみるよ | Futurismo

ビルドスクリプトとして、sConsが紹介されている。なかでも、感心したのが、スモークテストでのPytyonを利用した受け入れテストのアプローチ。pyhthonコードからシリアル接続を経由してテストする方法。この作者はPythonが好きなのかな?自分は、Rubyで同じことをやろうとした。

また、Valgrindを使ったメモリ破壊との戦いも、組込みならでは。こういうことにページを割くところも高評価。ValgrindはLinux用ツールなので、まだ使ったことがないけれども、今度調べてみようかな。

まとめ

組込みの現場ではなぜ、これらのテクニックが浸透しないのだろうか?

Eclipseが浸透しないのは、べつによい。エディタはEclipseだけではないし、EmacsやVimはEclipseに負けないくらいだ。

オブジェクト指向やデザインパターンが浸透しないのは、実行速度やメモリが関係しているのだろう。また、TDDもオブジェクト指向のほうが実施しやすい。(とくにMock)CIは、文化的なものだと思う。

どれも、決定的な理由にはならない。一つ思うのは

「無知」

だからということ。自分もCに関わるいろんな情報を集めているものの、ほかの言語とくらべて、Cは圧倒的に情報量が少ない。Eclipsしかり、TDDしかり、Jenkinsしかり。

C Programmerに足りないものは、道標となるような情報や、書籍だ。C言語は使用率第一位の言語なのだ。これからも、こういう書籍がドンドン出てきてほしい。

27 Oct 2013, 02:40

自由自在にコード内を飛び回る!Eclipseのコードリーディング機能が便利

Eclipseには、コードを読みやすくするための様々な機能が備わっています。

GUIだからマウスをたくさんつかうんだろうという迷信がありますが、実際はキーポードから手を離さなぽことがおおいです。

キーバインドを巧みに利用して、コード内を自由自在に飛び回るためのテクニックを紹介します。

[toc]

[//www.youtube.com/embed/db4vCH7oqG8?rel=0]

宣言を開く(F2,F3)

関数や宣言の場所へジャンプすることができます。いわゆる、タグジャンプ、EmacsのGNU Grobalのようなもの。もっともよく利用する機能です。

F3で飛んで、Alt + 左で元に戻る。これでソースコード内をマウスを利用せずにピョンピョンと移動することができます。

F2を押すと、飛ばずにポップアップで宣言の場所を表示することができます。

呼び出し階層を開く(Ctrl+Alt+h)

関数がメソッドがどこの関数から呼ばれているかを順々に表示してくれる機能。

リファクタリングの時の修正による影響範囲を調査する時、重宝する機能。

型階層を開く(F4)

クラスの型を階層的に表示てくれる機能。継承関係が分かる。

C++だと機能するけれども、Cだとよくわからない機能。あまり利用しない。

エディタバッファを開く(Ctrl + x + b)

ファイル間の移動は、ショートカットで新規にファイルを開くこともあるけれども、もともと開いているファイルに飛ぶこともデキる。

このキーバインドは、Emacsキーバインドを設定しているので、Emacsに慣れている人はそのキーバインドをそのままEclipseでも利用できる。すなわち、Ctrl + x + b。

Alt + 左で前へ戻り、Alt + 右で次へ進むことができる。もはやブラウザでWebページを見るような感じ。

検索で飛ぶ

デフォルトのEclipse CDT検索機能は利用しません。代わりに、プラグインを利用します。

検索結果をクリックするだけで検索箇所へジャンプできるので、コンソールからgrepして検索するよりも効率がよいです。

26 Oct 2013, 12:54

組込み開発の二大迷信に挑む!リファクタリングにおけるパフォーマンスとスタックオーバーフローについての数値実験

組込み開発において、リファクタリングしようとすると、自分は怒られる。

怒られるのが嫌で、リファクタリングできない。この2大迷信について、簡単な実験してみた。

Normalコード(Test1)

これは普通のコード。ここを参考にした。clock

[tsu-nera]% cat timer.c
#include <time.h>
#include <stdio.h>

int main(void)
{
  clock_t start, end;
  long l;
  long i=0;
  int  n=0;
  clock_t total_start, total_end;

  total_start = clock();

  while(n < 5){

    start = clock();
    i = 0;

    for (l=0; l<100000000; l++) {
      i++;
    }

    end = clock();
    printf("ループ1億回の時間: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
    n++;
  }

  total_end = clock();

  printf("平均の時間: %f秒\n", (double)(total_end - total_start) / CLOCKS_PER_SEC / n);

  return 0;

}

Functionコード(Test2)

つづいて、関数でインクリメントを抽出したコード。

[tsu-nera]% cat timer2.c
#include <time.h>
#include <stdio.h>


void incriment(long* i) {
  (*i)++;
}

int main(void)
{
  clock_t start, end;
  long l;
  long i=0;
  int  n=0;
  clock_t total_start, total_end;

  total_start = clock();

  while(n < 5){

    start = clock();
    i = 0;

    for (l=0; l<100000000; l++) {
      incriment(&i);
    }

    end = clock();
    printf("ループ1億回の時間: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
    n++;
  }

  total_end = clock();

  printf("平均の時間: %f秒\n", (double)(total_end - total_start) / CLOCKS_PER_SEC / n);

  return 0;

}

実験結果

気持ち、Test1のほうが早い気がする。もっと実験すれば、大数の法則で正確な値がでそうだけど、まあいいや。とりあえず、気持ちの問題で小さな関数はパフォーマンスをあまり低下させないという自身がついた。

Test1

[tsu-nera]% ./a.out
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 0.720000秒
ループ1億回の時間: 0.670000秒
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 1.170000秒
平均の時間: 0.932000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.030000秒
ループ1億回の時間: 0.960000秒
ループ1億回の時間: 0.960000秒
ループ1億回の時間: 0.770000秒
ループ1億回の時間: 0.680000秒
平均の時間: 0.882000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.250000秒
ループ1億回の時間: 0.840000秒
ループ1億回の時間: 0.670000秒
ループ1億回の時間: 0.570000秒
ループ1億回の時間: 0.630000秒
平均の時間: 0.792000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.030000秒
ループ1億回の時間: 0.730000秒
ループ1億回の時間: 0.630000秒
ループ1億回の時間: 0.520000秒
ループ1億回の時間: 0.460000秒
平均の時間: 0.674000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 0.940000秒
ループ1億回の時間: 0.720000秒
ループ1億回の時間: 0.630000秒
ループ1億回の時間: 0.540000秒
ループ1億回の時間: 0.500000秒
平均の時間: 0.666000秒

Test2

[tsu-nera]% ./a.out
ループ1億回の時間: 1.010000秒
ループ1億回の時間: 0.810000秒
ループ1億回の時間: 0.650000秒
ループ1億回の時間: 0.560000秒
ループ1億回の時間: 0.480000秒
平均の時間: 0.702000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.470000秒
ループ1億回の時間: 1.160000秒
ループ1億回の時間: 0.930000秒
ループ1億回の時間: 0.700000秒
ループ1億回の時間: 0.590000秒
平均の時間: 0.970000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 0.870000秒
ループ1億回の時間: 0.710000秒
ループ1億回の時間: 0.770000秒
ループ1億回の時間: 1.270000秒
平均の時間: 0.934000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.200000秒
ループ1億回の時間: 0.890000秒
ループ1億回の時間: 0.710000秒
ループ1億回の時間: 0.650000秒
ループ1億回の時間: 0.540000秒
平均の時間: 0.798000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.020000秒
ループ1億回の時間: 0.760000秒
ループ1億回の時間: 0.620000秒
ループ1億回の時間: 0.550000秒
ループ1億回の時間: 0.560000秒
平均の時間: 0.704000秒

スタックオーバーフローのテスト(Test3)

関数を呼びすぎるとスタックオーバーフローするよと脅されたが、脅した人はどのくらいの確信をもって発言したのかをテストした。

こんなサンプル。

#include <stdio.h>

void incriment(long* i) {
  (*i)++;
  printf("i=%d\n",*i);
  incriment(i);
}

int main(void)
{
  long  i=0;
  incriment(&i);
  return 0;

}

テスト結果

大体、自分のCygwin環境だと400000くらいでクラッシュする。

i=392880
i=392881
i=392882
[1]    18958 segmentation fault  ./a.out

ただ、スタックオーバーフローは、タスクサイズと環境依存なので、一概に安心はできないな。3階層くらいならば、へのようなものか(・・?

結論

関数抽出しても、コンパイラが最適化してくれるため、パフォーマンスは気にしない。小さな関数はコンパイラがinlineしてくれる。20年前の常識は、現代の非常識。

ただし、スタックオーバーフローは注意を払う。

22 Sep 2013, 15:24

重複コードを撃退!DRY原則をC言語で実践するためのCPDを調べた

はじめに

TDDが好きなので、コードの重複を計測するツール PMDについて調べてみた。

DRY原則とは

DRY原則とは、”Don’t Repeat YourSelf”の略。

簡単に言ってしまえば、コピペするな、ということだ。

重複なコードを書くならば、リファクタリングして、共通部分は共通化しようという考え方。

CPDで重複コードを計測する

このコードの重複さを計測するツールが PMDだ。PMD公式サイトから最新版をダウンロードする。

PMDはJAVA用のツールだが、それに付随するCPDというコマンドで、オプションにJAVA以外の言語を指定すると、他の言語でも使える。(C言語, C++, PHPとか)

Windowsの場合

<div class="outline-text-3" id="text-3-1">
  <p>
    zipファイルを解凍したら /bin配下に cpd.batというファイルがある。 これがコマンドラインから実行するためのコマンドになる。
  </p>

  <p>
    cpdの使い方は以下の通り。
  </p>

  <pre><code>cpd 

–minimum-tokens xxx 重複差を指定する。xxxを50にすれば50行以上の重複を報告 –files xxx ファイルのパス [–language xxx] 言語。自分はC言語を使いたいので –language c みたいな [–encoding xxx] エンコード指定 [–format (xml|text|csv|vs)] 出力フォーマット指定

  <p>
    例えば、重複度10でC言語でXML出力ならば、こんな感じ。
  </p>

  <pre><code>“C:\Program Files (x86)\pmd-bin-5.0-alpha\bin\cpd”

–minimum-tokens 10 –files src –language c –format xml>cpd_result.xml

  <p>
    最後にリダイレクトでファイルに出力してやる。
  </p>

  <p>
    現在の最新版 pmd 5.0だとエラーして苦労した。
  </p>

  <ul class="org-ul">
    <li>
      <i>CPDでsaxon9-dom.jarがないよと怒られ</i>
    </li>
  </ul>
</div>

Jenkins DRY Pluginを入れる

XML形式で出力した結果をJenkinsで表示してみる。

をJenkinsのプラグインで追加する。

プラグインをインストールすると、[ビルド後の処理の追加]で重複コード分析の集計が現れるので、さきほど出力したファイルを追加。

image

出力結果

image

 

はじめに

TDDが好きなので、コードの重複を計測するツール PMDについて調べてみた。

DRY原則とは

DRY原則とは、”Don’t Repeat YourSelf”の略。

簡単に言ってしまえば、コピペするな、ということだ。

重複なコードを書くならば、リファクタリングして、共通部分は共通化しようという考え方。

CPDで重複コードを計測する

このコードの重複さを計測するツールが PMDだ。PMD公式サイトから最新版をダウンロードする。

PMDはJAVA用のツールだが、それに付随するCPDというコマンドで、オプションにJAVA以外の言語を指定すると、他の言語でも使える。(C言語, C++, PHPとか)

Windowsの場合

<div class="outline-text-3" id="text-3-1">
  <p>
    zipファイルを解凍したら /bin配下に cpd.batというファイルがある。 これがコマンドラインから実行するためのコマンドになる。
  </p>

  <p>
    cpdの使い方は以下の通り。
  </p>

  <pre><code>cpd 

–minimum-tokens xxx 重複差を指定する。xxxを50にすれば50行以上の重複を報告 –files xxx ファイルのパス [–language xxx] 言語。自分はC言語を使いたいので –language c みたいな [–encoding xxx] エンコード指定 [–format (xml|text|csv|vs)] 出力フォーマット指定

  <p>
    例えば、重複度10でC言語でXML出力ならば、こんな感じ。
  </p>

  <pre><code>“C:\Program Files (x86)\pmd-bin-5.0-alpha\bin\cpd”

–minimum-tokens 10 –files src –language c –format xml>cpd_result.xml

  <p>
    最後にリダイレクトでファイルに出力してやる。
  </p>

  <p>
    現在の最新版 pmd 5.0だとエラーして苦労した。
  </p>

  <ul class="org-ul">
    <li>
      <i>CPDでsaxon9-dom.jarがないよと怒られ</i>
    </li>
  </ul>
</div></p>

Jenkins DRY Pluginを入れる

XML形式で出力した結果をJenkinsで表示してみる。

をJenkinsのプラグインで追加する。

プラグインをインストールすると、[ビルド後の処理の追加]で重複コード分析の集計が現れるので、さきほど出力したファイルを追加。

image

出力結果

<div class="outline-text-2" id="text-5">
  <a href="http://hmi-me.ciao.jp/wordpress/wp-content/uploads/image27.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://hmi-me.ciao.jp/wordpress/wp-content/uploads/image_thumb27.png" alt="image" width="566" height="281" border="0" /></a> </p> 

  <p>
    Jenkinsさんと一緒に思わずニンマリ。
  </p></p>
</div></p>