ソースコード書式

ソースコード書式


この「画像処理ライブラリ」は、【C++】言語で記載され
て居ますが、昭和の時代から【C】言語で自己流に
プログラミングを行った記法をベースにして居る為に多くの
平成以降でのコンピュータ学習系「高校・大学・専門学校」
で教わる方式と異なると感じる部分が有るかも知れませんの
で記法の特徴について説明して行きます!

この「画像処理ライブラリ」は、ソースコードで配布します
ので!自己責任≪自身でソースコードを弄っても内容が変わ
らない自信が有る人は、ご自身が、一番、理解し易い様に
自在に変更は可能です≫で改変して頂いても結構ですが、
オリジナルで無い事は理解して下さい!

1.タブストップとコメント

タイプライタ(機械式・電子式)しか使った事の無い方や、
PC作業でもワープロ(Wordの様なワードプロセッサー
)しか使った事の無い方にはヒョットシテ、「タブストップ
を設定」する意味とか使用方法を理解して無い場合が、
有ると思い「老婆心」から簡単に説明≪キーボードに
「Tab」と言う特殊なキーが有る事は御存知ですね?!
Tabキーを押すと空白文字が自動的に複数個打った様に
移動します!
そしてTabキーを押す度に移動した位置は、横方向に
上下の行でも同じ位置に成る事は理解して居ますね!
タイプライタやWord等の初期設定では、その位置(
ストップ位置)は、8・16・24・32・40・・・と
8文字単位に成って居る筈です!
そして「タブストップを設定」するとは、このストップ位置
を作成する文章(テキスト・コンピュータ言語では文字に
よるプログラミング)の種類毎に都合の良い様に位置を設定
出来る機能で【C言語系では、4・8・12・16・・・と
4文字単位を使用する人が多い】≫、そして私も4文字単位
を使用して居ます?!
次は、コメントです!元々の【C】言語は、
以下のNoteコード機能で示した様に

/* これは、コメントです */

と【/*】で「コメントの始まり」と【*/】で「コメントの終
わり」を示し、フリーフォーマット(自由書式)で記載出来
ます!因みに!

/* これは、行を跨いだコメントです
中身1行目・・・
中身2行目・・・
・・・・
中身の最終行
 */

と複数行も≪/*・・コメント・・*/≫とコメントに成り
ます!さて、【C】言語を進化させた【C++】言語では、
「ポカヨケ」≪この場合、「/*」でコメントが始まるが、
「*/」を書き忘れて記載したプログラムがコンパイラに
依って本文までコメントと見なされる事を防ぐ為の進化し
た手段として「//」から始まり「改行」までをコメントと
する記法が生まれた!≫

// これは、コメントです
a = b * c; // 変数aに変数bと変数cの乗算結果を代入

の様に「左端から始まる本文」を説明するコメントが記載
出来ます!
実は、私は、「コメントが嫌いです」⇒「文法に即して記載
されたプログラミング本体から、意味を読み取れ」と
常常つねづね思って居たが、このライブラリは、
会社(もう消滅したがベンチャー企業ADS社)の業務とし
て行ったのと記述量が膨大に成り、不遜にも「自分で記載し
た物は覚えて居る筈」との能力限界を超えた為に
「メモ書き」として必要に成った為に記載したのだ!
但し、本文の中に埋め込む時、出来るだけ、本文と
コメントを離して記載
し本文の記述が醜く成る事を避ける
為に、纏まった記載は、本文(C言語文法で記載された部分
でクラス・構造体・「#define」定義の塊)の前には、
行の全てをコメントにしたコメント部を前置する事にしま
した!

// CopyClear.h: CopyClear クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////////

とファイル自体の説明とか

/********************************************************************************************/
/*****  内部で使用するデータ                                                            *****/
/********************************************************************************************/

protected:

    int     m_swDegreeRadian;                       // 0:ディグリー/ 1:ラジアン

};

性質が変わる「public」属性から「protected」属性に
変わる事を説明するコメントとして記載します!
更に、個別の本文の内容を説明する為にコメントと分かり
易い様に右端にコメントの始まりを以下の様に揃えて

#include    "Support.h"                             // サポート関数定義部


class CopyClear : public Support                    // クラス定義
{
private:
    struct          TypeSort {                      // ソート用データ構造
        short       key;                            // ソートキー部
        short       ix;                             // ソートインデックス部
    };                                              // 型名「TypeSort」

public:
    CopyClear();                                    // コンストラクタ
    virtual ~CopyClear();                           // デストラクタ

public:                                             // 画像関数として正規に見せるもの
                                                    // 画像クリア/画像コピー
    int     Clear(                                  // クリア:汎用
                TypeArray*  pa,                     //  配列
                int         data );                 //  データ

説明の始まりを示します!
私としては、コメントはブロックとして記載しています!
世の中には、説明が必要な極近くにコメントを置いた方が
良いと考える近接主義者がいますが、私は、コメントが
下手に混ざると見難く醜く成ると思ってシマウ人です!
※尚、上記のCode機能の中身は、一旦、Tabキーで
空白が入った物をテキストエディタで空白に変換した物を
使用して居ます!
NoteのCode機能では、Tabストップ設定機能が
有るのかも知れ無いが、
8・16・24・32・40・・・と飛んでしまい不都合
だからです※

2.インデント

ソースコードのインデント(字下げ)としてプログラムの
構造を見易くする為に制御構文の内側にある行などの先頭に
一律に同じ幅の空白を挿入する事をインデントと言い。
この「画像処理ライブラリ」のソースコードでもデータ構造
≪「class」クラス構造・「struct」構造体≫や
制御構文≪「if」構文・「while」構文・「for」構文・
「switch、case、default」構文≫等にインデントを
使用して居ますが、注意深く見て頂ければ、ヒョットシテ
「学校で教えられた方式と異なる」場合が有るかも知れま
せんので先ず、データ構造

class TypeArray                                         // クラス名「TypeArray」
{
public:
    TypeArray();                                        // コンストラクタ
    virtual ~TypeArray();                               // デストラクタ
    int     Malloc( int w1, int h1, int v1 );           // 総合型配列メモリ確保&定義
    int     MallocByte(   int h1, int v1 );             // BYTE型配列メモリ確保&定義
    int     MallocShort(  int h1, int v1 );             // short型配列メモリ確保&定義
    int     MallocInt(    int h1, int v1 );             // int型配列メモリ確保&定義
    int     MallocFloat(  int h1, int v1 );             // float型配列メモリ確保&定義
    int     MallocDouble( int h1, int v1 );             // double型配列メモリ確保&定義
    int     SetByte(   int a, int h1, int v1 );         // BYTE型配列定義
    int     SetShort(  int a, int h1, int v1 );         // short型配列定義
    int     SetInt(    int a, int h1, int v1 );         // int型配列定義
    int     SetFloat(  int a, int h1, int v1 );         // float型配列定義
    int     SetDouble( int a, int h1, int v1 );         // double型配列定義
    int     SetByte(   void* p, int h1, int v1 );       // BYTE型配列定義
    int     SetShort(  void* p, int h1, int v1 );       // short型配列定義
    int     SetInt(    void* p, int h1, int v1 );       // int型配列定義
    int     SetFloat(  void* p, int h1, int v1 );       // float型配列定義
    int     SetDouble( void* p, int h1, int v1 );       // double型配列定義
    int     subset(                                     // 部分配列の定義
                TypeArray*  orgPtr,                     // 元へのポインタ
                int x, int y,                           // 始点xy座標
                int h1, int v1 );                       // 水平・垂直幅
    int     subsetAdjust(                               // 部分配列の定義:幅自動調整
                TypeArray*  orgPtr,                     // 元へのポインタ
                int x, int y,                           // 始点xy座標
                int h1, int v1 );                       // 水平・垂直幅
    int     subsetBMP(                                  // 部分配列の定義:表示用BMP専用
                TypeArray*  orgPtr,                     // 元へのポインタ
                int x, int y,                           // 始点xy座標:カラー画素単位
                int h1, int v1 );                       // 水平・垂直幅:カラー画素単位
    int     subsetRev(                                  // 部分配列の定義:表示用BMP専用
                TypeArray*  orgPtr,                     // 元へのポインタ
                int x, int y,                           // 始点xy座標:個別画素単位
                int h1, int v1 );                       // 水平・垂直幅:個別画素単位
    int     get( int x, int y );                        // 画素取り出し
    double  getReal( int x, int y );                    // 画素取り出し:実数
    void    put( int x, int y, int d );                 // 画素書き込み
    void    put( int x, int y, double d );              // 画素書き込み
    int     getDataInt( int x, int y );                 // データ取りだし:4バイト整数
    int     getDataShort( int x, int y );               // データ取りだし:2バイト整数
    void    putDataInt( int x, int y, int d );          // データ書き込み:4バイト整数
    void    putDataShort( int x, int y, int d );        // データ書き込み:2バイト整数

public:                     // 構造体の内部変数(画像サイズ&画素型)
    int         adr;        // アドレス
    int         h;          // 水平方向大きさ(実範囲)
    int         v;          // 垂直大きさ
    int         inc;        // 水平方向大きさ(垂直増加用)0:1次
    char        w;          // 処理幅(1/2/4BYTE,101:単精度,102:倍精度)

public:                                                     // inline 関数
    inline int  maxX(void){ return( h - 1 ); }              // 最大X座標
    inline int  maxY(void){ return( v - 1 ); }              // 最大Y座標
    inline int  size(void){ return( h * v ); }              // 画素数
    inline int  sizePix(void)                               // BYTE換算単位サイズ
    {                                                       // 
        if( w == 101 ){                                     // 単精度なら 
            return( 4 );                                    // 4を答えとする
        }else if( w == 102 ){                               // 倍精度なら
            return( 8 );                                    // 8を答えとする
        }else{                                              // 1/2/4BYTEなら
            return( w );                                    // 左記で算出
        }                                                   // 
    }                                                       // 
    inline int  sizeMem(void){                              // メモリサイズ
            return( size() * sizePix() ); }                 // =画素数×単位サイズ
    inline int  sizeInc(void){                              // BYTE換算増加幅
            return( inc * sizePix() ); }                    // =増加幅×単位サイズ
    inline void freeMem(void)                               // メモリ解放
    {                                                       // 
        if( adr != 0 ){                                     // メモリ取得済みなら
            free( (void*)adr );                             // メモリを解放し
            adr = 0;                                        // アドレスを初期化
        }                                                   // 
    }
    inline int  check( int x, int y ){                      // 検査:全般
        if( adr <= 0 || x < 0 || x >= h                     // アドレスや
                                    || y < 0 || y >= v ){   // 座標が不正なら、
            return( STI_FLG );                              // 不正を返す
        }                                                   // 
        return( END_STI );                                  // 正常終了
    }
    inline int  checkXY( int x, int y ){                    // 検査:座標
        if( x < 0 || x >= h || y < 0 || y >= v ){           // 座標が不正
            return( STI_FLG );                              // なら、不正を返す
        }                                                   // 
        return( END_STI );                                  // 正常終了
    }
    inline int  getByte( int x, int y ){                    // 画素取り出し
            return( *( (BYTE*)adr + x + y * inc ) ); }      // BYTE単位
    inline int  getShort( int x, int y ){                   // 画素取り出し
            return( *( (short*)adr + x + y * inc ) ); }     // short単位
    inline int  getInt( int x, int y ){                     // 画素取り出し
            return( *( (int*)adr + x + y * inc ) ); }       // int単位
    inline double getFloat( int x, int y ){                 // 画素取り出し
            return( *( (float*)adr + x + y * inc ) ); }     // 単精度単位
    inline double getDouble( int x, int y ){                // 画素取り出し
            return( *( (double*)adr + x + y * inc ) ); }    // 倍精度単位
    inline void putByte( int x, int y, int d ){             // 画素書き込み
            *( (BYTE*)adr + x + y * inc ) = d; }            // BYTE単位
    inline void putShort( int x, int y, int d ){            // 画素書き込み
            *( (short*)adr + x + y * inc ) = d; }           // short単位
    inline void putInt( int x, int y, int d ){              // 画素書き込み
            *( (int*)adr + x + y * inc ) = d; }             // int単位
    inline void putFloat( int x, int y, double d ){         // 画素書き込み
            *( (float*)adr + x + y * inc ) = (float)d; }    // 単精度単位
    inline void putDouble( int x, int y, double d ){        // 画素書き込み
            *( (double*)adr + x + y * inc ) = d; }          // 倍精度単位
    inline BYTE*    getPtrByte( int x, int y ){             // 画素アクセスポインタ取出
                return( (BYTE*)adr + x + y * inc ); }       // BYTE単位
    inline short*   getPtrShort( int x, int y ){            // 画素アクセスポインタ取出
                return( (short*)adr + x + y * inc ); }      // short単位
    inline int*     getPtrInt( int x, int y ){              // 画素アクセスポインタ取出
                return( (int*)adr + x + y * inc ); }        // int単位
    inline float*   getPtrFloat( int x, int y ){            // 画素アクセスポインタ取出
                return( (float*)adr + x + y * inc ); }      // 単精度単位
    inline double*  getPtrDouble( int x, int y ){           // 画素アクセスポインタ取出
                return( (double*)adr + x + y * inc ); }     // 倍精度単位
};

ココでは、「TypeArray」クラスの定義を行って居ます!
このクラスが、「画像処理ライブラリ」の画像を意味し、
操作対象に成るデータ構造です!
ここで、よもやま話≪画像だから、「image」とかの名前に
成るのではと思われた読者様も多数いらしゃるでしょう!
元々は、ベンチャー企業ADS社の画像処理装置を動作させ
る為の組み込みコンピュータソフトウェアだったので
元々「TypeImage」と称する構造体「元々C言語しか存在
しない時代に開発された為だからstruct定義です」
アナログの画像同期信号に合わせて駆動するLSI「小さな
会社だったが、最小ロットGA(ゲートアレーと称する半導
体メーカーにカスタム特注品)を作成」とディスクリート
回路で構成された専用のアナログ映像信号をデジタルに
量子化して画像メモリー間で昭和の時代にビデオレートと
当時としては極めて高速動作するハードウェアを制御する為
の情報を格納する構造体が「TypeImage」で画像用のデータ
構造として使用していた時、超高速に動作するハードウェア
では細かい画像処理が出来無いので副次的にCPUで処理す
る為に「TypeArray」構造体を準備したのが、
名称の始まりです!この「struct TypeArray」を使用した
ソフトウェアでの画像処理が、CPUが高速化した昨今、
CPUだけで専用のハードウェアの代りに出来る様にしたの
が「TypeArray」クラスです≫、よそ道に逸れましたが、
「class TypeArray」が、行の先頭(左端)から始まってい
ます!
そして右側に≪// クラス名「TypeArray」≫とコメントを
配してます!次の行に改行したら、行の先頭(左端)に
「{」と波括弧(中括弧)の括弧開くだけを記載し、即、
改行して居ます!C++文法的に対応する「}」波括弧
(中括弧)の閉じ括弧までが、「class TypeArray」範囲
です!
その次も行の先頭(左端)から始まっています!
ココは、異論が有る可能性が有りますが、「public:」と
コノ行以下を「public詰り、クラス外へも参照&使用可能な
定義」で有る事を示す!
重要なキーワードなのでコノ位置にしました!
次に一段、インデントされた所から「TypeArray();」と
クラスが使用する側でコノTypeArrayをデータタイプとして
変数を定義した時に最初に動作する「コンストラクタ」と
呼ばれるメンバー関数の定義が始まります!
次の行で「virtual ~TypeArray(); 」と「デストラクタ」と
呼ばれるメンバー関数の定義が始まります!
デストラクタは、後始末用です!意味はC++言語の
マニュアル(文法規則)を読んで下さい!
次は、「int Malloc(」から「int SetDouble(」メンバー
関数(メソッド)の定義文です!
コンストラクタ・デストラクタと同じく、一段、インデント
された場所から始まり
「Malloc( int w1, int h1, int v1 ); 」と仮引数の並びを
「()」丸括弧(小括弧)で囲み「;」で終えて右方に
コメントを付けています!
次の「int subset(」は、仮引数の並びが1行内に収まら
無いので「,」で本文は改行し行を跨いで記述しています!
先ず、「subset(」と「(」丸括弧(小括弧開く)で改行しま
す!
この記載法の利点としては、「int subset(」と関数名まで
記載した後で改行し、中身の仮引数の並びを分けて記載した
方が分かり易いし、個別に意味をコメントで説明可能だから
です!
恐らく、異論が有るとしたら、「int h1, int v1 ); 」と
コノ仮引数の並び最後の「);」を独立して無い事でしょう
が、私としては、少しでも行数を少なくしたかったのです!
さて、インデントですが、一段で無く複数段下げ、
関数名の始まり依りも後方に配置しました、インデントは
文法で無く美意識です!
だから、見易いと思える方式で記載して居ます!
同じ様に「int subset」とまで記載し、
「(」丸括弧(小括弧開く)を独立行として開き括弧≪
「(」・「[」・「{」・「<」≫等を一行で記載出来ない
文を跨ぐ場合は、改行する記法も≪開き括弧は、右側に有る
べし≫と頭の硬い固定観念の持ち主は、主張するでしょう
が、私は、関数名とか制御構文の場合は、左側で始めても良
いと考えています!勿論、美意識からです!
さて、続きですが、特徴の有る部分は、
「inline int sizePix(void) 」で始まる「sizePix」
メソッドの定義ですが、ココは、インライン定義で実際に
使用した部分に「{}」波括弧(中括弧で囲まれた展開部)を
記述しています!ココは、関数の実体を定義して居るので
「inline」と同じ位置で「{」開き括弧と「}」閉じ括弧の
位置を合わせ、中身を一段インデントし、
「if( w == 101 ){」とif文「ココでは、変数が101数値と
等価検査」し、条件が成立したら「{return( 4 ); }」と
インデントを一段下げて実行する部分を示します!
「){」とif文の条件終わりに実行するブロックの始まりを
示す「{」波括弧(中括弧)は、「)」if文条件終わり
小括弧の直後に付け、アタカも「if( w == 101 ){」の
行自体がif構文の始まり括弧として上方に記載した
括弧開くと解釈して居ます!
この記法でなく「{」を独立して1行だけ括弧開くを表す
事を推奨した記載法も有りますが私は、余分に間延びして
しまうと美意識からコウ記載したのです!
※ここで記載した様に「{」開き波括弧を独立した「{」だけ
で記載して居るのは、クラス定義の本文の記載と
関数(メソッド)の記載だけです!
文法的には、関数の実行分中「{}」でブロックを記載出来
ますが、単にブロックの部分は無く、
if・while・for等の制御構文の中に組み込まれ
ています!※
例外的な記載!

    struct          TypeSort {                      // ソート用データ構造
        short       key;                            // ソートキー部
        short       ix;                             // ソートインデックス部
    };                                              // 型

ここでクラス定義に関しては、「{」開き波括弧を独立した
「{」だけで記載して居る事を説明しましたが、
上記のCodeに載せた「struct」構造体の場合は、
「{」開き波括弧が構造体名の後にと右側に付けて居ます!
勿論、昭和の時代に作成した構造体の名残です!
クラス定義が使える様に成ったC++記載で合わせよう
とも考えたのだが、例外として「struct」構造体は残しまし
た!これは、コレで見慣れていたからです!

この記事が気に入ったらサポートをしてみませんか?