marunomaruno-memo

marunomaruno-memo

[C++] メンバー関数の関数ポインターをメンバー変数にする

2014年06月20日 | C / C++
                                                        2014-06-20 新規
[C++] メンバー関数の関数ポインターをメンバー変数にする
======================================================================

(MinGW gcc (GCC) 4.5.4)

クラスのメンバー関数への関数ポインターの定義と使用。


□ funcpointer.cpp
---
#include <iostream>
using namespace std;

class A {
private:
    int data;
    int (A::*fp[2])(int data);  // (1) インスタンス関数のポインター

public:
    A(int data) :
            data(data), fp({&A::func, &A::func2}) { // (2)
    }

    int exec(int index, int data) {
        return (this->*fp[index])(data);    // (3)
    }

private:
    int func(int data) {
        return this->data + data;
    }
    int func2(int data) {
        return this->data - data;
    }
};

int main() {
    A a(100);
    cout << "0: " << a.exec(0, 10) << endl; // (4)
    cout << "1: " << a.exec(1, 20) << endl;

    return 0;
}
---

□ 実行結果
---
0: 110
1: 80
---

(1) インスタンス関数ポインターの配列

通常のメンバー関数ポインターの配列と同じ。

    int (A::*fp[2])(int data);  // (1) インスタンス関数のポインター


(2) インスタンス関数ポインターの配列の初期値

    A(int data) :
            data(data), fp({&A::func, &A::func2}) { // (2)
    }

コンストラクターの初期化リストで、
    fp({&A::func, &A::func2})
ということはできないかと思ったが、どうやらできる。
ただし、つぎの警告が出る。
    extended initializer lists only available with -std=c++0x or 
    -std=gn
u++0x
コンパイルするときに上記のオプションを指定すれば、警告は出なくなる。


(3) 関数ポインターの配列を実行するメンバー関数

    return (this->*fp[index])(data);    // (3)

this ポインターを使わないといけない。使わずに、
    (fp[index])(data)
とすると、つぎのコンパイルエラー。
    must use '.*' or '->*' to call pointer-to-member function in 
    '((A*)this)->A::fp[index] (...)', e.g. 
    '(... ->* ((A*)this)->A::fp[index]) (...)'

メンバー関数のポインターは、".*" か "->*" を使わないといけないからかな。


(4) 実行

たんに、メンバー関数を呼んでいるだけ。最初の引数はメンバー関数のポイン
ターの配列の添字を指定している。
    cout << "func(): " << a.exec(0, 10) << endl; // (4)

メンバー関数のポインターの配列 fp を public にして、main() 関数でつぎの
ように使おうとしても、
    (a.*fp[0])(30)
コンパイルエラー。
    'fp' was not declared in this scope
まあ、上記の書き方だと、main 関数の中で fp を定義しないとだめだ。


                                                                   以上


[C++] 関数テンプレートのポインター

2014年06月19日 | C / C++
                                                        2014-06-19 新規
[C++] 関数テンプレートのポインター
========================================================================
(MinGW gcc (GCC) 4.5.4)

□ functionpointer_template.cpp
---
#include <iostream>
using namespace std;

template<class T>   // (1)
T square(T a) {
    return a * a;
}

template<class T, class F>  // (2)
T calc(T a, F func){
    return func(a);
}

int main() {
    int (*p)(int) = square; // (3) この使い方はあまり意味ない感じ
    cout << p(2) << endl;   // (4)
    cout << p(3.4) << endl; // (5) 

    cout << calc(2, square<int>) << endl;   // (6) 
    cout << calc(3.4, square<double>) << endl;  // (7)
//  cout << calc(5, square) << endl;    // コンパイルエラー

    return 0;
}
---

□ 実行結果
---
4
9
4
11.56
---

(1) 関数テンプレートの宣言

(2) 関数テンプレートのポインターを引数に持つ関数テンプレートの宣言

(3) 関数テンプレートを実体化したものを関数ポインターに設定

関数ポインターは、通常の関数ポインターと変わりはない。テンプレートの型は
自分で設定している。
    int (*p)(int) = square; // (3) この使い方はあまり意味ない感じ


(4)(5) 関数ポインターの利用

int 型の引数を取るので、そのまま使う。
    cout << p(2) << endl;   // (4)

int 型の引数を取るので、double 型の引数を渡しても、int 型として処理され
る。
    cout << p(3.4) << endl; // (5) 


(6)(7) 関数テンプレートのポインターを引数に持つ関数テンプレートの利用

int 型を明示しているの、int 型の引数の square 関数ポインターを渡す。
    cout << calc(2, square<int>) << endl;   // (6) 

double 型を明示しているの、double 型の引数の square 関数ポインターを渡す。
    cout << calc(3.4, square<double>) << endl;  // (7)

つぎのように、データ型を明示していないと、コンパイルエラーになる。
    calc(5, square)

    no matching function for call to 'calc(int, <unresolved 
    overloaded function type>)'

                                                                   以上


[C++] メンバー関数の関数ポインター

2014年06月13日 | C / C++
                                                        2014-06-17 追記
                                                        2014-06-13 新規
[C++] メンバー関数の関数ポインター
========================================================================

(MinGW gcc (GCC) 4.5.4)

クラスのメンバー関数への関数ポインターの定義と使用。


□ funcpointer.cpp
---
#include <iostream>
using namespace std;

class A {
private:
    static int staticdata;
    int data;

public:
    A(int data) :
            data(data) {
    }

    static int staticfunc(int data) {
        return data - staticdata;
    }

    int func(int data2) {
        return data + data2;
    }
};

int A::staticdata = 777;

int main() {
    A a(111);

    cout << "staticfunc(): " << A::staticfunc(999) << 
endl;
    cout << "func(): " << a.func(222) << endl;

    cout << " 関数ポインター " << endl;
    int (*sfp)(int data) = A::staticfunc;   // (1) static 関数ポインター
    cout << "staticfunc(): " << sfp(888) << endl;   //
 (2)

    int (A::*fp)(int data2) = &A::func; // (3) インスタンス関数のポ
インター
    cout << "func(): " << (a.*fp)(333) << endl; // (4)

    return 0;
}
---



□ 実行結果
---
staticfunc(): 222
func(): 333
関数ポインター
staticfunc(): 111
func(): 444
---

(1) static 関数ポインターの定義と初期化

    int (*sfp)(int data) = A::staticfunc;

通常のグローバル関数の関数ポインターと同じように定義する。
関数ポインターは、
    クラス名 :: 関数名
という形で取得する。

定義部分には、クラス名の要素が入っていないので、他のクラスでも同じシグネ
チャーの関数なら、この関数ポインターを使うことができる。

たとえば、B クラスに同じシグネチャーの
    static int staticfunc(int data)
があれば、
    sfp = B::staticfunc;
として、関数ポインターを設定できる。


(2) static 関数ポインターの利用

    cout << "staticfunc(): " << sfp(888) << endl;

通常のグローバル関数の関数ポインターと同じように利用すればよい。


(3) インスタンス関数ポインターの定義と初期化

関数ポインター名の前に、「A::」をつけておく。

    int (A::*fp)(int data2) = &A::func;

スコープ解決しないと、つぎのコンパイルエラーが出る。
    cannot convert 'int (A::*)(int)' to 'int (*)(int)' in initialization

関数ポインターは、
    & クラス名 :: 関数名
という形で取得する。「&」がないとコンパイルエラーになる。
    invalid use of non-static member function 'int A::func(int)'


(4) インスタンス関数ポインターの利用

    cout << "func(): " << (a.*fp)(333) << endl;

インスタンス a を使う。したがって、少し、違和感はあるが、次のような形で
利用する。
    (インスタンス名 .* 関数ポインター名)(引数のリスト)

インスタンスがないと使えないので、
    fp(333) 
では、つぎのコンパイルエラーが出る。
    must use '.*' or '->*' to call pointer-to-member function in 
'fp (...)', 
    e.g. '(... ->* fp) (...)'

もちろん、クラス A のメンバー関数用なので、まったく同じシグネチャーを持
つ別のクラスのメンバー関数のインスタンスで使おうとしても、コンパイルエ
ラー。
    B b;
    (b.*fp)(333)
では、つぎのエラー。
    pointer to member type 'int (A::)(int)' incompatible with object 
type 'B'



■ メンバー関数ポインターのポリモーフィズム (2014-06-17 追記)

上記 A クラスを継承した D クラスをつきのように定義する。

---
class D : public A {
public:
    D(int data) :
            A(data) {
    }

    int func(int data) {
        return data * 2;
    }

};
---

このメンバー関数 func() は、基底クラス A のメンバー関数 func() をオー
バーライドしている。
この D クラスのインスタンスを基底クラス A 型として扱う。

つぎのようなコードを上にサンプルに追加する。
---
    A* d = new D(11);   // (5)
    fp = static_cast<int (A::*)(int)> (&D::func);   // (6)
    cout << "func(): " << (d->*fp)(333) << endl; // (7)
---

この部分の実行結果としては、つぎのようになる。
---
func(): 666
---

A クラスの型だが、D クラスのメンバー関数 func() を実行しているのが確認で
きる。



(5) A クラスの型として、D クラスのインスタンスを生成する。

    A* d = new D(11);   // (5)


(6) D クラスのオーバーライドしているメンバー関数 func を、A クラスの関数
ポインターに代入する

    fp = static_cast<int (A::*)(int)> (&D::func);   // (6) 

このとき、アップキャストすることになるが、不思議なことに、static_cast が
必要。


(7) D クラスのインスタンスを使って、この関数ポインターが指す関数を実行す
る

    cout << "func(): " << (d->*fp)(333) << endl; // (7)


インスタンスのポインター d を使う。したがって、少し、違和感はあるが、次
のような形で利用する。
    (インスタンスのポインター名 ->* 関数ポインター名)(引数のリスト)


                                                                   以上
---
2014-06-17 追記 メンバー関数のポリモーフェィズム
---



[Java] 昔作ったJavaの問題とサンプル解答

2014年01月20日 | Java
[Java]
昔作ったJavaの問題とサンプル解答
表示
http://blog.goo.ne.jp/marunomarunogoo/d/20100617

算術演算子
http://blog.goo.ne.jp/marunomarunogoo/d/20100618

変数
http://blog.goo.ne.jp/marunomarunogoo/d/20100622

分岐
http://blog.goo.ne.jp/marunomarunogoo/d/20100624

ループ
http://blog.goo.ne.jp/marunomarunogoo/d/20100628

配列(1)
http://blog.goo.ne.jp/marunomarunogoo/d/20100710

配列(2)
http://blog.goo.ne.jp/marunomarunogoo/d/20100711

2次元配列
http://blog.goo.ne.jp/marunomarunogoo/d/20100712

メソッド(1)
http://blog.goo.ne.jp/marunomarunogoo/d/20100714

メソッド(2)
http://blog.goo.ne.jp/marunomarunogoo/d/20100715


あけましておめでとうございます

2014年01月01日 | Weblog
今年もよろしくお願いいたします。




ポニーに人参あげた。口もと(鼻先)の動きがなんともいえない。

[C] 可変長引数の関数から可変長引数の関数を呼ぶ

2013年10月27日 | C / C++
                                                                2013-10-27 新規
[C] 可変長引数の関数から可変長引数の関数を呼ぶ
================================================================================

可変長引数の関数から、別の可変長引数の関数を呼び出す。

gcc の拡張機能で、可変長マクロもあるが、あくまでも gcc 拡張なので、可変長引数を
持つ関数を使う。

サンプルとしては、デバッグ用のプリント関数をつくることにする。

デバッグ用なので、マクロ名 NDEBUG が定義されているときは何もしないようにする。そ
して、プリントした後に改行し、flush も行う。

また、プリントする関数なので、標準ライブラリー関数 printf() のように、可変長の引
数を受け取るようにする。

仕様としては、以下のとおり。
    void debugPrint(const char* tag, const char* format, ...);

    引数
        tag     タグ。
        format  プリントする書式
        ...     可変長引数部分。プリントしたい式や値

なお、この関数の中から、可変長リストを引数にとる関数を呼び出すことにする。
仕様としては、以下のとおり。
    void print(const char* tag, const char* format, va_list args);

    引数
        tag     タグ
        format  プリントする書式
        args    可変長リスト


□ vargs_sample.c
---
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> // (1)

void debugPrint(const char* tag, const char* format, ...);  // (2)
void print(const char* tag, const char* format, va_list args);  // (3)

int main(void) {
    printf("Start¥n");

    debugPrint("TEST", "[%d %d]", 123, 456);    // (4)

    printf("End¥n");

    return EXIT_SUCCESS;
}

void debugPrint(const char* tag, const char* format, ...) {
#ifndef NDEBUG      // (5)
    va_list args;   // (6)
    va_start(args, format); // (7)
    print(tag, format, args);   // (8)
    va_end(args);   // (9)
#endif
}

void print(const char* tag, const char* format, va_list args) {
    printf("%s ", tag);
    vprintf(format, args);  // (10)
    putchar('¥n');
    fflush(stdout);
}
---

□ 実行結果
---
Start
TEST [123 456]
End
---


(1) #include <stdarg.h>

可変長引数を持った関数を宣言するために必要なヘッダーファイル。


(2) void debugPrint(const char* tag, const char* format, ...);

可変長引数を持った関数のプロトタイプ宣言。
少なくとも、ひとつは引数が必要になる。
だいたいは、この引数に続く可変長部分の形式や数をあらわすものになる。

この使い方は、標準ライブラリー関数の printf() と同じ。
ただし、デバッグ用として、改行が入り、出力した後に flush する。
また、マクロ名 NDEBUG が定義されているときは何も表示しない。


(3) void print(const char* tag, const char* format, va_list args);

可変長の引数をあらわすリスト va_list 型の引数を受け取る関数のプロトタイプ宣言。
この関数は、可変長引数部分を
    const char* format, ...
としてしまうと、実行結果は正しくなくなるので注意。


(4) debugPrint("TEST", "[%d %d]", 123, 456);

可変長の引数を持った関数の呼び出し。
ここでは、デバッグ用のプリント関数 debugPrint() を使っている。


(5) #ifndef NDEBUG

デバッグ用のプリント関数なので、マクロ名 NDEBUG が定義されているときは何も行わな
いようにする。


(6) va_list args;

可変長引数部分をあらわす (可変長リスト) 型 va_list の変数 args を定義する。


(7) va_start(args, format);

可変長リストを初期化する。
最初の引数は、va_list 型の変数。ここに、可変長リストが入る。
2 番目の引数は、可変長引数の直前の引数名。


(8) print(tag, format, args);

可変長リストを引数としてもつ関数の呼び出し。
普通の関数の呼び出しと一緒。


(9) va_end(args);

可変長リストの処理を終了する。


(10) vprintf(format, args);

可変長リストを持った標準ライブラリー関数 printf 関数の呼び出し。
この部分を、
    printf(format, args);
とすると、実行結果は正しくないので注意が必要。


                                                                            以上



[C] 外部変数(グローバル変数)の定義(仮定義)

2013年03月21日 | Android
                                                                    2013-03-21
[C] 外部変数(グローバル変数)の定義(仮定義)
================================================================================

何のキーワードもつけない外部変数を 2 つのモジュールで定義すると、片一方は自動的
に extern がついた扱いになる。
ただし、2 つとも初期値を設定すると、リンクで二重定義となりエラー。
これって C の仕様かな。それとも、gcc 固有の拡張か? (gcc 3.4)

どうやら、C 言語の仕様。
仮定義というもの。リンケージ時に仮定義の中のひとつが定義になる。


ヘッダー・ファイルで外部変数を定義するときに、初期値をつけないことにしておけば、
extern をつけたり、つけなくしたりするための条件コンパイルや、マクロ定義は必要なく
なるなあ。


□ global_test.c
---
#include <stdio.h>
#include <stdlib.h>

void func(void);

int global = 1234;    // (1)

int main(void) {
    printf("main: %d\n", global);
    func();
    return EXIT_SUCCESS;
}
---

□ global_test2.c
---
#include <stdio.h>
#include <stdlib.h>

void func(void);

int global;    // (2)

void func(void) {
    printf("func: %d\n", global);
}
---

□ 実行結果
---
main: 1234
func: 1234
---

□ nm コマンドの結果
---
00402000 D _global
---


(1)と(2)の組合せで、nm コマンドの結果(シンボル・タイプ)
    ------------------- ----------- ------------------
    (1)\(2)            int global; int global = 1234;
    ------------------- ----------- ------------------
    int global;               B            D
    int global = 1234;        D           (*)
    ------------------- ----------- ------------------
    (*) リンケージでエラー(multiple definition of `global')

nm コマンドは、指定されたライブラリ内に存在するシンボルのリストを表示する。
シンボル・タイプは以下のとおり。
    T (コードセクション内の普通の定義)
    D (初期化されたデータセクション)
    B (初期化されないデータセクション)
    U (未定義。シンボルはライブラリによって使われているが、ライブラリ内では定義
       されていない)
    W (weak. もしも他のライブラリも同じシンボルを定義している場合、その定義によ
       りオーバーライドされる)

参考: 
Program Library HOWTO > 5. 雑録 > 5.1. nm コマンド
http://archive.linux.or.jp/JF/JFdocs/Program-Library-HOWTO/miscellaneous.html


ついでに、
JIS X3010「プログラム言語C」6.9.2 外部オブジェクト定義 の例1
を示す。

□ global_tes3.c
---
int i1 = 1;           // 定義、外部結合
static int i2 = 2;    // 定義、内部結合
extern int i3 = 3;    // 定義、外部結合
int i4;               // 仮定義、外部結合
static int i5;        // 仮定義、内部結合

int i1;               // 正しい仮定義、前の定義を参照する
//int i2;             // 前に内部結合を持つ定義があるため、結合の不一致が生じ、
                      // "6.2.2 識別子の結合" によって動作は未定義となる
int i3;               // 正しい仮定義、前の定義を参照する
int i4;               // 正しい仮定義、前の定義を参照する
//int i5;             // 前に内部結合を持つ定義があるため、結合の不一致が生じ、
                      // "6.2.2 識別子の結合" によって動作は未定義となる

extern int i1;        // 外部結合を持つ前の定義を参照する
extern int i2;        // 内部結合を持つ前の定義を参照する
extern int i3;        // 外部結合を持つ前の定義を参照する
extern int i4;        // 外部結合を持つ前の定義を参照する
extern int i5;        // 内部結合を持つ前の定義を参照する
---

□ global_test4.c
---
//int i1 = 1;         // 定義、外部結合    ※二重定義になるのでコメントアウト
static int i2 = 2;    // 定義、内部結合
//extern int i3 = 3;  // 定義、外部結合    ※二重定義になるのでコメントアウト
int i4;               // 仮定義、外部結合
static int i5;        // 仮定義、内部結合

int i1;               // 正しい仮定義、前の定義を参照する
//int i2;             // 前に内部結合を持つ定義があるため、結合の不一致が生じ、
                      // "6.2.2 識別子の結合" によって動作は未定義となる
int i3;               // 正しい仮定義、前の定義を参照する
int i4;               // 正しい仮定義、前の定義を参照する
//int i5;             // 前に内部結合を持つ定義があるため、結合の不一致が生じ、
                      // "6.2.2 識別子の結合" によって動作は未定義となる

extern int i1;        // 外部結合を持つ前の定義を参照する
extern int i2;        // 内部結合を持つ前の定義を参照する
extern int i3;        // 外部結合を持つ前の定義を参照する
extern int i4;        // 外部結合を持つ前の定義を参照する
extern int i5;        // 内部結合を持つ前の定義を参照する
---

□ nm コマンドの結果
---
00402004 D _i1
00402008 d _i2
00402000 d _i2
0040200c D _i3
004040b0 B _i4
00404020 b _i5
00404010 b _i5
---

シンボル・タイプで、小文字はそのシンボルがローカルであることを意味し、大文字はそ
のシンボルがグローバル (外部定義) であることを意味する。


                                                                            以上



今年もよろしくお願いいたします

2013年01月07日 | Weblog
このお正月はリアルに寝正月でした。
外は気持ちよいですね。
明日からは散歩にも行こう。

今年もよろしくお願いいたします。

CUnit: C 用 単体テスト・フレームワーク

2012年11月30日 | C / C++
                                                                    2012-11-30
CUnit: C 用 単体テスト・フレームワーク
================================================================================

■ Cunit

Cunit は、 C プログラムの単体テストをするためのフレームワークです。
このドキュメントでは、単純な使い方だけを示します。


ダウンロードとインストール

つぎからダウンロードします
CUnit
http://sourceforge.net/projects/cunit/

任意のフォルダーに展開すればインストール完了です。
このドキュメントでは、
    C:¥CUnit-2.1-0
にインストールしたことにします。


■ サンプル

サンプルとして、指定された西暦年に対して、うるう年か平年かを検査する関数 
isLeapYear() のモジュール LeapYear.c の単体テストを考えます。


□ LeapYear.h
---
/*
 * LeapYear.h
 *
 *  Created on: 2012/08/15
 *      Author: maruno
 */

#ifndef LEAPYEAR_H_
#define LEAPYEAR_H_

/**
 * 西暦 year 年がうるう年かどうか判定する。
 * @param year 西暦年
 * @return うるう年のとき1、平年のとき0
 */
int isLeapYear(int year);


#endif /* LEAPYEAR_H_ */
---


□ LeapYear.c
---
#include "LeapYear.h"

int isLeapYear(int year) {
    if ((year % 4) == 0) {
        if ((year % 100) == 0) {
            return 0;
        }
        if ((year % 400) == 0) {
            return 1;
        }
        return 1;
    }
    return 0;
}
---


■ Cunit の使用法

1. テスト・ドライバーの作成

まず、単体テストを行いたいモジュールのテスト・ドライバーを作ります。

□ LeapYearTest.c
---
#include <stdlib.h>
#include <CUnit.h>
#include <Automated.h>
#include <Basic.h>

#include "LeapYear.h"

void testIsLeapYear001(void);
void testIsLeapYear002(void);
void testIsLeapYear003(void);
void testIsLeapYear004(void);

int main(void) {
    CU_pSuite suite;

    CU_initialize_registry();
    suite = CU_add_suite("isLeapYear", NULL, NULL );
    CU_ADD_TEST(suite, testIsLeapYear001);
    CU_ADD_TEST(suite, testIsLeapYear002);
    CU_ADD_TEST(suite, testIsLeapYear003);
    CU_ADD_TEST(suite, testIsLeapYear004);
    CU_automated_run_tests();            // 結果をXML形式で出力
    CU_basic_set_mode(CU_BRM_NORMAL);    // 結果表示を失敗と実行サマリーにする
    CU_basic_run_tests();    // 結果を標準出力に出力
    CU_cleanup_registry();

    return 0;
}

/**
 * 400の倍数でうるう年
 */
void testIsLeapYear001(void) {
    CU_ASSERT_EQUAL(1, isLeapYear(2000));    // 2つの引数が等しければOK
}

/**
 * 4の倍数でうるう年
 */
void testIsLeapYear002(void) {
    CU_ASSERT_TRUE(isLeapYear(2012));    // 結果がtrueであればOK
}

/**
 * 100の倍数で平年
 */
void testIsLeapYear003(void) {
    CU_ASSERT_FALSE(isLeapYear(2100));    // 結果がfalseであればOK
}

/**
 * 4で割り切れず平年
 */
void testIsLeapYear004(void) {
    CU_ASSERT(0 == isLeapYear(2013));    // 条件式の結果がtrueであればOK
}
---

>gcc -IC:¥CUnit-2.1-0¥include¥CUnit -Wall -c LeapYearTest.c
>gcc -c -Wall LeapYear.c
>gcc -LC:¥CUnit-2.1-0¥lib -o test.exe leapYear.o LeapYearTest.o -lcunit


2. ビルドと実行

ビルド
---
>gcc -IC:¥CUnit-2.1-0¥include¥CUnit -Wall -c LeapYearTest.c
>gcc -c -Wall LeapYear.c
>gcc -LC:¥CUnit-2.1-0¥lib -o test.exe leapYear.o LeapYearTest.o -lcunit
---

※ CUnit を C:¥CUnit-2.1-0 にインストールしています。


実行

実行すると、標準出力に実行結果が出ます。
これとあわせて、つぎの結果ファイルができます。
    CUnitAutomated-Results.xml 
同じフォルダに、C:¥CUnit-2.1-0¥share¥CUnit にある
    CUnit-Run.dtd
    CUnit-Run.xsl
をコピーして、CUnitAutomated-Results.xml をダブルクリックすると、IE が立ち上がり、
グラフィカルに単体テストの結果を見ることができます。


□ 実行結果
---
>test

     CUnit - A Unit testing framework for C - Version 2.1-0
     http://cunit.sourceforge.net/


Suite isLeapYear, Test testIsLeapYear001 had failures:
    1. LeapYearTest.c:35  - CU_ASSERT_EQUAL(1,isLeapYear(2000))

--Run Summary: Type      Total     Ran  Passed  Failed
               suites        1       1     n/a       0
               tests         4       4       3       1
               asserts       4       4       3       1
---



なお、すべてパスするように修正した後の実効結果は以下のようになります。
---
     CUnit - A Unit testing framework for C - Version 2.1-0
     http://cunit.sourceforge.net/

--Run Summary: Type      Total     Ran  Passed  Failed
               suites        1       1     n/a       0
               tests         4       4       4       0
               asserts       4       4       4       0
---


■ ASSERT マクロ

代表的なマクロとして、以下のようなマクロが用意されています。

    CU_ASSERT(式)
    CU_ASSERT_TRUE(式)
    CU_ASSERT_FALSE(式)
    CU_ASSERT_EQUAL(式1, 式2)
    CU_ASSERT_NOT_EQUAL(式1, 式2)
    CU_ASSERT_PTR_EQUAL(ポインタ1, ポインタ2)
    CU_ASSERT_PTR_NOT_EQUAL(ポインタ1, ポインタ2)
    CU_ASSERT_PTR_NULL(ポインタ)
    CU_ASSERT_PTR_NOT_NULL(ポインタ)
    CU_ASSERT_STRING_EQUAL(文字列1, 文字列2)
    CU_ASSERT_STRING_NOT_EQUAL(文字列1, 文字列2)
    CU_ASSERT_NSTRING_EQUAL(文字列1, 文字列2, 文字数)
    CU_ASSERT_NSTRING_NOT_EQUAL(文字列1, 文字列2, 文字数)
    CU_ASSERT_DOUBLE_EQUAL(実数1, 実数2, 精度)
    CU_ASSERT_DOUBLE_NOT_EQUAL(実数1, 実数2, 精度)
    CU_PASS(メッセージ文字列)
    CU_FAIL(メッセージ文字列)


■ 参考

CUnit
http://sourceforge.net/projects/cunit/

CUnit チュートリアル
http://homepage3.nifty.com/kaku-chan/cunit/index.html

                                                                            以上



[C] gprof: プロファイラ・プログラム

2012年11月29日 | Android
                                                                    2012-11-29
gprof: プロファイラ・プログラム
================================================================================

■gprof

gprof は、プロファイラとして、つぎのことを測定します。

・コードの各セクションが消費する計算時間 


コンパイル時に -pg オプションをつけることで使えるようになります。


■gprof の使用法

1. コンパイル

コンパイル時に -pg オプションをつけることで使えるようになります。

>gcc -Wall -pg prof_sample.c

コンパイルすると、つぎのファイルができます。
    prof_sample.gcno 


□ prof_sample.c
---
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>

#define MAX (10 * 1000)

void sort(int a[], int size);
void swapIfDesc(int a[], int i, int j);
void swap(int a[], int i, int j);

int main(void) {
    int a[MAX];
    int i;
    puts("program start");
    fflush(stdout);
    for (i = 0; i < MAX; ++i) {
        a[i] = rand();
    }

    long start = clock();

    sort(a, MAX);

    printf("%6ld ms¥n", (clock() - start));
    fflush(stdout);

    for (i = 1; i < MAX; ++i) {
        assert(a[i-1] <= a[i]);
    }

    puts("program end");
    fflush(stdout);
    return EXIT_SUCCESS;
}

void sort(int a[], int size) {
    int i, j;

    for (i = 0; i < size; ++i) {
        for (j = i; j < size; ++j) {
            swapIfDesc(a, i, j);
        }
    };
}

void swapIfDesc(int a[], int i, int j) {
    if (a[i] >= a[j]) {
        swap(a, i, j);
    }
}

void swap(int a[], int i, int j) {
    int w = a[i];
    a[i] = a[j];
    a[j] = w;
}
-----------------------------------------------------------


2. 実行

>a.exe
---
program start
  3062 ms
program end
---


3. プロファイルを見る

つぎのように、gprof コマンドを使って、測定した結果を見ます。

> gprof a.exe


□ 実行結果
---
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls   s/call   s/call  name
 53.21      0.83     0.83 50005000     0.00     0.00  swapIfDesc
 33.33      1.35     0.52        1     0.52     1.56  sort
 13.46      1.56     0.21 24964410     0.00     0.00  swap

 %         the percentage of the total running time of the
time       program used by this function.
            (全体の総実行時間に対するその関数の総実行時間の占める割合)

cumulative a running sum of the number of seconds accounted
 seconds   for by this function and those listed above it.
            (その関数より上位に示されているすべての関数の総実行時間と,
            その関数の総実行時間の累積時間(秒))

 self      the number of seconds accounted for by this
seconds    function alone.  This is the major sort for this
           listing.
            (その関数の総実行時間(秒))

calls      the number of times this function was invoked, if
           this function is profiled, else blank.
            (その関数が呼び出された総回数)

 self      the average number of milliseconds spent in this
ms/call    function per call, if this function is profiled,
           else blank.
            (その関数の一回の呼び出しに対する平均実行時間(ミリ秒))

 total     the average number of milliseconds spent in this
ms/call    function and its descendents per call, if this
           function is profiled, else blank.
            (その関数の一回の呼び出しに対する,その関数とその関数に呼び出された
            サブルーチンの平均実行時間(ミリ秒))

name       the name of the function.  This is the minor sort
           for this listing. The index shows the location of
           the function in the gprof listing. If the index is
           in parenthesis it shows where it would appear in
           the gprof listing if it were to be printed.

                     Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) for 0.64% of 1.56 seconds

index % time    self  children    called     name
                0.52    1.04       1/1           main [2]
[1]    100.0    0.52    1.04       1         sort [1]
                0.83    0.21 50005000/50005000     swapIfDesc [3]
-----------------------------------------------
                                                 <spontaneous>
[2]    100.0    0.00    1.56                 main [2]
                0.52    1.04       1/1           sort [1]
-----------------------------------------------
                0.83    0.21 50005000/50005000     sort [1]
[3]     66.7    0.83    0.21 50005000         swapIfDesc [3]
                0.21    0.00 24964410/24964410     swap [4]
-----------------------------------------------
                0.21    0.00 24964410/24964410     swapIfDesc [3]
[4]     13.5    0.21    0.00 24964410         swap [4]
-----------------------------------------------

 This table describes the call tree of the program, and was sorted by
 the total amount of time spent in each function and its children.

 Each entry in this table consists of several lines.  The line with the
 index number at the left hand margin lists the current function.
 The lines above it list the functions that called this function,
 and the lines below it list the functions this one called.
 This line lists:
     index      A unique number given to each element of the table.
                Index numbers are sorted numerically.
                The index number is printed next to every function name so
                it is easier to look up where the function in the table.
                (関数につけられる連続した番号)

     % time     This is the percentage of the `total' time that was spent
                in this function and its children.  Note that due to
                different viewpoints, functions excluded by options, etc,
                these numbers will NOT add up to 100%.
                (全実行時間に対するその関数の総実行時間(その関数から呼び出された
                サブルーチンの実行時間も含む) の割合)

     self       This is the total amount of time spent in this function.
                (その関数の総実行時間)

     children   This is the total amount of time propagated into this
                function by its children.
                (その関数に呼び出されたサブルーチンの総実行時間)

     called     This is the number of times the function was called.
                If the function called itself recursively, the number
                only includes non-recursive calls, and is followed by
                a `+' and the number of recursive calls.
                (その関数が呼び出された総回数)

     name       The name of the current function.  The index number is
                printed after it.  If the function is a member of a
                cycle, the cycle number is printed between the
                function's name and the index number.


 For the function's parents, the fields have the following meanings:

     self       This is the amount of time that was propagated directly
                from the function into this parent.

     children   This is the amount of time that was propagated from
                the function's children into this parent.

     called     This is the number of times this parent called the
                function `/' the total number of times the function
                was called.  Recursive calls to the function are not
                included in the number after the `/'.

     name       This is the name of the parent.  The parent's index
                number is printed after it.  If the parent is a
                member of a cycle, the cycle number is printed between
                the name and the index number.

 If the parents of the function cannot be determined, the word
 `<spontaneous>' is printed in the `name' field, and all the other
 fields are blank.

 For the function's children, the fields have the following meanings:

     self       This is the amount of time that was propagated directly
                from the child into the function.

     children   This is the amount of time that was propagated from the
                child's children to the function.

     called     This is the number of times the function called
                this child `/' the total number of times the child
                was called.  Recursive calls by the child are not
                listed in the number after the `/'.

     name       This is the name of the child.  The child's index
                number is printed after it.  If the child is a
                member of a cycle, the cycle number is printed
                between the name and the index number.

 If there are any cycles (circles) in the call graph, there is an
 entry for the cycle-as-a-whole.  This entry shows who called the
 cycle (as parents) and the members of the cycle (as children.)
 The `+' recursive calls entry shows the number of function calls that
 were internal to the cycle, and the calls entry for each member shows,
 for that member, how many times it was called from other members of
 the cycle.


Index by function name

   [1] sort                    [4] swap                    [3] swapIfDesc
---


□ オプション

-b         説明部分を省略
-p         Flat profile のみを出力
-P         Call graph のみを出力
-c         関数内部で使われる関数についての使用状況も出力
-z         実行時に使っていない関数や時間を計測できない程度の関数も、使用状況を出力
-e 関数名  指定した関数の出力を結果から除く

                                                                            以上


ロボロボロボコン2012

2012年11月01日 | LEGO
ロボロボロボコン2012
http://www.enjoy-robo.com/images/pdf/roboroborobocon2012_book.pdf

ロボロボロボコンとは
レゴNXTマインドストームを使用したロボット大会です。小学2年生から大人まで、誰でも参加できます。レースは、年齢に関係なく同じレースで競い合います。

ロボットレースを通じて、”考える楽しさ”を共有する場所です。(前身の「クリスマスロボコン」が2010年から始まり、今年で3回目を迎えます。)

日時:12月16日(日) 11時~16時30分
場所:かながわ労働プラザホールB
http://www.zai-roudoufukushi-kanagawa.or.jp/?l-plaza/
レース:鬼ごっこレース!
(A)自走型部門
(B)ラジコン部門

お申込み http://www.enjoy-robo.com/form_roborobo/
お問い合わせ info@enjoy-robo.com

※まだ、募集しておりますので、興味のある方はお問い合わせください。

[C++] 自分自身のインスタンスを定数で持つクラス

2012年10月08日 | Android
自分自身のインスタンスを定数で持つクラス
================================================================================

自分自身のインスタンスを定数で持つクラスのサンプル。

メンバー変数は、たんに int 型の値を持っているだけ。
コンストラクターをすべて private にすれば、他から直接インスタンスを生成できない
ようにすることもできる。


□ Item.h
---
#ifndef ITEM_H_
#define ITEM_H_

#include <iostream>

class Item {
public:
    static const Item* ITEM1;    // (1)
    static const Item* ITEM2;    // (1)

    static const Item* ITEM_LIST[];    // (2)
    static const int ITEM_LIST_SIZE;    // (3)

private:
    int value;

public:
    Item();
    Item(int value);
    virtual ~Item();

    int getValue() const;
};

#endif /* ITEM_H_ */
---

(1) 自分自身のオブジェクトの定数の宣言

    static const Item* ITEM1;    // (1)
    static const Item* ITEM2;    // (1)

(2)(3) オブジェクト定数配列の宣言とその要素数の宣言

オブジェクト定数を配列で持っていることで、使い勝手が向上するかもしれない。
そのときの要素数も持たせておく。

    static const Item* ITEM_LIST[];    // (2)
    static const int ITEM_LIST_SIZE;    // (3)

ここで、ITEM_LIST_SIZE は int 型だから、
    static const int ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
                / sizeof(Item::ITEM_LIST[0]);
とすると、つぎのメッセージでコンパイルエラーとなる。
    invalid application of `sizeof' to incomplete type `const Item*[]' 
この時点では、ITEM_LIST の要素が確定していないため。


□ Item.cpp
---
#include <iostream>
#include <cassert>
#include "Item.h"

const Item* Item::ITEM1 = new Item(10);    // (1)
const Item* Item::ITEM2 = new Item(20);    // (1)

const Item* Item::ITEM_LIST[] = { ITEM1, ITEM2 };    // (2)
const int Item::ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
        / sizeof(Item::ITEM_LIST[0]);    // (3)

Item::Item() {
    assert(true);
}

Item::Item(int value) :
        value(value) {
    assert(true);
}

Item::~Item() {
    assert(true);
}

int Item::getValue() const {
    return value;
}
---

(1) 自分自身のオブジェクトの定数の定義

const Item* Item::ITEM1 = new Item(10);    // (1)
const Item* Item::ITEM2 = new Item(20);    // (1)


(2) オブジェクト定数配列の定義

const Item* Item::ITEM_LIST[] = { ITEM1, ITEM2 };    // (2)


(3) オブジェクト定数配列の要素数の定義

const int Item::ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
        / sizeof(Item::ITEM_LIST[0]);    // (3)


□ ItemTest.cpp
---
#include <iostream>
using namespace std;

#include "Item.h"

int main() {
    cout << Item::ITEM1->getValue() << endl;
    cout << Item::ITEM2->getValue() << endl;

    for (int i = 0; i < Item::ITEM_LIST_SIZE; ++i) {
        cout << Item::ITEM_LIST[i]->getValue() << endl;
    }

    Item item;
    cout << item.getValue() << endl;

    Item item2(30);
    cout << item2.getValue() << endl;

    return 0;
}
---


□ 実行結果
---
10
20
10
20
0
30
---

                                                                            以上



[C++][STL] vector にオブジェクトを入れるときのクラスの注意点

2012年09月14日 | Android
■ [C++][STL] vector にオブジェクトを入れるときのクラスの注意点

・vector にオブジェクトを入れるときに、そのコピーコンストラクターの引数は const でなければならない。
const にしないとビルドエラーになる。
うっかり付け忘れても、普通に使っている分には問題ないかもしれないが、vector なんかに入れようとすると怒られる。

ついでに、vector に入れるためには、コピーコンストラクターだけではなく、引数のないコンストラクター、デストラクターが必要。また、自分でコピーコンストラクターを作らないといけない状況の場合は、代入演算子のオーバーロードも必要になってくる。

そういえば、前、関係演算子(== や <) もオーバーロードが必要なものがあったような、なかったような。。。vector の場合は、なくても平気かな。


□ vector_sample.cpp
---
#include <iostream>
#include <vector>
using namespace std;

class A {
public:
    A() {}
    A(A& r) {}    // A(const A& r) ならOK
};

int main() {
    vector<A> v;
    v.push_back(A());    // no matching function for call to `A::A(A)'
to `A::A(const A&)'
    return 0;
}
---


□ ビルド結果
---

**** Build of configuration Debug for project vector_sample ****

**** Internal Builder is used for build               ****
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src/vector_sample.o ../src/vector_sample.cpp
../src/vector_sample.cpp: In function `int main()':
../src/vector_sample.cpp:21: error: no matching function for call to `A::A(A)'
../src/vector_sample.cpp:16: note: candidates are: A::A(A&)
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_construct.h: In function `void std::_Construct(_T1*, const _T2&) [with _T1 = A, _T2 = A]':
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_vector.h:560:   instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]'
../src/vector_sample.cpp:21:   instantiated from here
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_construct.h:81: error: no matching function for call to `A::A(const A&)'
../src/vector_sample.cpp:16: note: candidates are: A::A(A&)
../src/vector_sample.cpp:15: note:                 A::A()
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/vector.tcc: In member function `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]':
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_vector.h:564:   instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]'
../src/vector_sample.cpp:21:   instantiated from here
C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/vector.tcc:234: error: no matching function for call to `A::A(const A&)'
../src/vector_sample.cpp:16: note: candidates are: A::A(A&)
Build error occurred, build is stopped
Time consumed: 1047  ms.  
---

                                                                        以上


C言語による組込み制御入門講座―H8マイコンで学ぶプログラミングとデバッグ技法

2012年08月11日 | 組込み
C言語による組込み制御入門講座―H8マイコンで学ぶプログラミングとデバッグ技法 [単行本]
大須賀 威彦 (著)

単行本: 311ページ
出版社: 電波新聞社 (2006/06)
ISBN-10: 4885549167
ISBN-13: 978-4885549168
発売日: 2006/06
商品の寸法: 20.8 x 14.8 x 2.2 cm

組込み制御の基礎
H8/300Hの概要
開発環境のインストール
コンパイルとリンク
シミュレーション
実機デバッグ
C言語の基礎
データ入出力
割込み処理のプログラム
タイマのプログラム
A/D変換とD/A変換のプログラム
ストップウォッチのプログラム


俺のコードのどこが悪い?―コードレビューを攻略する40のルール

2012年07月15日 | Weblog
俺のコードのどこが悪い?―コードレビューを攻略する40のルール [単行本]
藤原 克則 (著)
http://www.shuwasystem.co.jp/products/7980html/2918.html

価格: 2100円(税込)(本体2000円)
単行本: 295ページ
出版社: 秀和システム (2011/03)
ISBN-10: 4798029181
ISBN-13: 978-4798029184
発売日: 2011/03
商品の寸法: 23.4 x 18.2 x 2.2 cm

ダウンロード
http://www.shuwasystem.co.jp/support/7980html/2918.html

正誤
http://www.lares.dti.ne.jp/~foozy/fujiguruma/books.html#codereview-book.errata

著者
http://www.lares.dti.ne.jp/~foozy/fujiguruma/books.html#codereview-book

★レビュー準備編
●1 レビューを効率良く進めるために
1.1 全体像を素早く掴むための準備
1.2 コードの参照性を高めるための準備
●2 レビューでの指摘を活かすために
2.1 「失敗学」とは?
2.2 失敗の分類
2.3 原因の究明
2.4 失敗への対策
2.5 添付チェックシートについて
●3 レビューでの指摘を恐れないために
3.1 「評価」と「技能」
3.2 「責任の共有」と考える
3.3 「指摘がない」のは良いことか?
3.4 「間違える」のは「難しい」から

★レビュー実践編
■機能充足性
●01 if/else文での判定条件は適切ですか?
01.01 判定条件に漏れはありませんか?
01.02 判定順序は適切ですか?
01.03 判定方法は最適化されていますか?
●02 データ型は適切ですか?
02.01 変数型の値域は十分ですか?
02.02 比較対象の型は一致していますか?
●03 ループの終了判定は妥当ですか?
03.01 必要な変数がすべて初期化されていますか?
03.02 終了判定の対象は適切な変数ですか?
03.03 終了条件は適切ですか?
03.04 更新処理に漏れはありませんか?
03.05 構文選択は妥当ですか?
●04 switch文のcaseラベル列挙は十分ですか?
04.01 caseラベルの列挙に漏れはありませんか?
04.02 default節は明記してありますか?
●05 引数チェックは十分ですか?
05.01 前提条件の確認を実装していますか?
05.02 前提条件を明記していますか?
●06 戻り値チェックは十分ですか?
06.01 戻り値の仕様は確認済みですか?
06.02 獲得したリソースの解放は適切ですか?

■リソース消費
●07 引数チェックが多過ぎませんか?
07.01 引数チェックは十分軽量ですか?
07.02 関数の呼び出し関係を把握していますか?
●08 戻り値チェックが多過ぎませんか?
08.01 戻り値チェックは十分軽量ですか?
08.02 関数の仕様は確認済みですか?
●09 関数の局所変数が多過ぎませんか?
09.01 未使用変数はないですか?
09.02 通用範囲は妥当ですか?
●10 各行の負荷を把握していますか?
10.01 引数による負荷の変動を把握していますか?
10.02 ループ内での関数呼び出しは軽いですか?
10.03 排他獲得状態は把握していますか?
●11 似たような処理があちこちにありませんか?
11.01 その処理は本当に必要ですか?
11.02 その処理は集約できませんか?
11.03 処理を似せる工夫はしていますか?
●12 不要な条件判定をしていませんか?
12.01 引数/戻り値チェックとの重複はありませんか?
12.02 その条件は成立し得ますか?
●13 構造体渡しは必要ですか?
13.01 構造体のサイズは妥当ですか?
13.02 他から参照されていませんか?
13.03 コンストラクタ/デストラクタは妥当ですか?
●14 不要な関数呼び出しをしていませんか?
14.01 関数の戻り値を処理に使っていますか?
14.02 その関数には副作用がありますか?
●15 関数呼び出しのコストを把握していますか?
15.01 引数の数は妥当ですか?
15.02 ライブラリ形式は妥当ですか?
●16 例外に頼り過ぎていませんか?
16.01 条件判定で済みませんか?
●17 スレッド間同期の方法は適切ですか?
17.01 同期の必要性は認識していますか?
17.02 同期手順は適切ですか?
17.03 同期方法は適切ですか?
17.04 同期対象は明確ですか?
●18 アルゴリズムやデータ構造の選択は適切ですか?
18.01 最大データ量の見積もりはどの程度ですか?
18.02 改変頻度の見積もりはどの程度ですか?
18.03 どんなアクセス方式を想定していますか?
●19 コンパイラの最適化に期待し過ぎていませんか?
19.01 関数横断での最適化を期待していませんか?
19.02 メモリ配置での最適化を期待していませんか?
●20 ファイルアクセスは妥当ですか?
20.01 ファイルアクセスは最小限ですか?
20.02 mmap()の使用は検討済みですか?
20.03 ディレクトリ構成は妥当ですか?
20.04 システムの制限は把握していますか?

■実行安全性
●21 入力データは検証済みですか?
21.01 どこまで信用できるデータですか?
21.02 サイズの妥当性は検証済みですか?
21.03 内容の妥当性は検証済みですか?
●22 スタック消費量は妥当ですか?
22.01 局所変数は最小限ですか?
22.02 関数呼び出しの深さは妥当ですか?
●23 ヒープ消費量は妥当ですか?
23.01 総データ量の見積もりは済んでいますか?
23.02 未使用領域を解放していますか?
●24 スレッド数は十分ですか?
24.01 スレッド数は十分ですか?
24.02 スレッド数が過剰ではないですか?
●25 ファイル操作は妥当ですか?
25.01 ファイル更新手順は妥当ですか?
25.02 ファイルシステム境界は意識していますか?
25.03 時間当たりの転送量の見積もりは済んでいますか?
●26 ネットワークアクセスは妥当ですか?
26.01 連携先との接続障害に備えていますか?
26.02 連携タイミングに関する前提は妥当ですか?
26.03 時間当たりの転送量の見積もりは済んでいますか?
●27 異常が検出された際の挙動は適切ですか?
27.01 継続可能な異常ですか?
27.02 不要なリソースは解放していますか?
27.03 異常への対応位置は妥当ですか?

■保守性
●28 横に長いコードになっていませんか?
28.01 ループや条件判定の入れ子が多過ぎませんか?
28.02 関数引数が多過ぎませんか
28.03 式が複雑過ぎませんか?
●29 空行を適切に挿入していますか?
29.01 関連する処理はどれですか?
29.02 関連するデータはどれですか?
●30 プロジェクトのコーディング規約に従っていますか?
30.01 プロジェクトにコーディング規約はありますか?
30.02 規約チェック用のツールはありますか?
●31 自分のコーディングスタイルは一貫していますか?
31.01 各行の体裁が一貫していますか?
31.02 関数宣言の体裁が一貫していますか?
31.03 関数定義の体裁が一貫していますか?
●32 機能を詰め込み過ぎていませんか?
32.01 引数による条件判定が多過ぎませんか?
32.02 関数の行数が多過ぎませんか?
●33 変更をどこまで想定していますか?
33.01 その値は変更されませんか?
33.02 その処理は変更されませんか?
●34 名前付けは適切ですか?
34.01 具体性はありますか?
34.02 対称性/相似性はありますか?
34.03 データ型が変わっても通じますか?

■拡張性
●35 無駄な拡張性にこだわっていませんか?
35.01 どの程度の拡張性を想定していますか?
35.02 安全性は考慮されていますか?
●36 十分な情報を受け渡していますか?
36.01 実現される機能範囲は想定済みですか?
36.02 情報の受け渡し方法は妥当ですか?

■テスト容易性
●37 環境に依存する箇所は把握していますか?
37.01 別のホスト上でもテストできますか?
37.02 別のシステム構成でもテストできますか?
37.03 別のOS/CPUアーキテクチャ上でもテストできますか?
●38 テスト環境の構築は簡単ですか?
38.01 必要なソフトウェアの入手は簡単ですか?
38.02 必要なハードウェアの入手は簡単ですか?
38.03 事前状態の作成は簡単ですか?
●39 日付と時刻の扱いを考えていますか?
39.01 テストデータの準備はどうしていますか?
39.02 「今日」「今」を扱いますか?
●40 どこまで細分化したテストを行えますか?
40.01 テスト対象関数は呼び出せますか?
40.02 組み合わせバリエーションは把握済みですか?
40.03 エラー系のテストはできますか?
40.04 タイミング依存の処理はテストできますか?
あとがき
レビューチェックシート
分類先決定のためのフローチャート