STM32資料 発展編1

構造体を使ってみよう

発展編では、センサーのライブラリ作成を目標にしてもらいます

そのためには、クラスという複雑な概念を少し理解してプログラムに組み込まなくてはなりません

そこで、クラスの簡易版的なものである構造体から学んでみましょう

構造体とは

構造体は、複数の変数をまとめて保管できる型です

具体例を見たほうがわかりやすいので、id、位置、速度、加速度のデータをまとめるDataという構造体を作ってみます

構造体の定義

struct Data{

    //どんな変数型でも定義可能
    uint8_t axis = "x"; //軸
    uint32_t time = 0; //測定時間
    float potision = 0.0; //位置
    float velocity = 0.0; //速度
    float acceleration = 0.0; //加速度
};

このように、構造体を使うことで変数をまとめて扱うことができる

構造体の中に含まれている変数をメンバー変数というので覚えておこう

構造体の使い方

構造体は、intやfloatのような変数型と同じように扱われるため、変数を宣言する必要がある

少しややこしい書き方ですが、Data型のdataという変数をこのように作成できる

Data data; //構造体の変数を作成

dataの中に含まれている変数は、data.potisionのように"."を使って表すことができる

このdata.potisionはintやfloatなどの変数と同じように計算したりif文で比較したりできる

実際の使用例

構造体は変数型と同じように扱えるため、同じ変数型で名前の違う構造体を作成できる

先ほど定義した構造体は位置、速度、加速度を1つずつしか持つことができないので、3次元を表すために

それぞれの軸用の変数を作成する

Data data_x;
Data data_y;
Data data_z;

これらは別の変数として扱われるため、各軸にそれぞれの値を代入することができる

data_x.potison = 1.0; //x軸の位置
data_y.potison = 2.0; //y軸の位置
data_z potison = 3.0; //z軸の位置

作成した構造体の問題点

自由にアクセスできる

構造体は便利で分かりやすいが、変数を管理する上での問題点がある

例えば、data_x.Positionが0から1の数直線上の値であったとしよう

この構造体のメンバー変数にはどこからでもアクセスできるので、

長いコードのどこかでこのように書いてしまうこともできる

data_x.Positon = 100;

これが制御に関するものだったら事故に繋がるかもしれない(思いっきり壁に突っ込んでしまう)

関数を使ったアクセス管理

範囲外の値を好きなところから入力できることは大きな問題なので、

値を判定し、問題ない場合のみ代入する関数を作ってみよう

void SetPotision(float Value){

    //値が範囲外のとき
    if(Value > 1.0 || Value < 0.0){
        
        //エラー
    }
    //値が範囲内のとき
    else{

        potision = Value; //値を代入   
    }
}

構造体に関数を追加

紹介した関数を構造体に入れてみる

これで値を外部から入れたい時は、SetPotision関数を使えば大丈夫!

struct Data{

    float potision = 0.0; //位置
    float velocity = 0.0; //速度
    float acceleration = 0.0; //加速度

    void SetPotision(float Value){

        //値が範囲外のとき
        if(Value > 1.0 || Value < 0.0){
            
            //エラー
        }
        //値が範囲内のとき
        else{

            potision = Value; //値を代入   
        }
    }
};

アクセス権の設定

これで解決できた、、、と思ってしまうが

このコードで値を直接操作できてしまうので、さっきの問題は消えていない

data_x.Positon = 100;

そこでアクセス権を指定する

ここでは、public, privateというキーワードが出てくる

publicとprivateの違い

操作 Public Private
外部からのアクセス できる できない
内部からのアクセス(メンバー関数での使用) できる できる

したがって、SetPotision関数を外部から操作可能にして

Postionは内部(=SetPotision関数)からしか操作できないようにすることで

範囲外の値を勝手に書き込まれる事態を防ぐことができる

アクセス権の設定方法

この設定をした構造体が下のコードになる

構造体は初期で外部からアクセス可能(=public)であるので、privateのみ書いている

potisionは外部からアクセスできないため、外部から値を取得するための

GetPotision()関数も作成した

struct Data{

    float velocity = 0.0; //速度
    float acceleration = 0.0; //加速度
            
    //Positonに値を代入
    void SetPotision(float Value){

        //値が範囲外のとき
        if(Value > 1.0 || Value < 0.0){
            
            //エラー
        }
        //値が範囲内のとき
        else{
        
            potision = Value; //値を代入   
        }
    }

    //Positonから値を取得
    float GetPotision(){
        return potision; //値を取得
    }

    private:

        float potision = 0.0; //位置
};

一見コードが長くなってわかりにくくなったように感じるかもしれないが、

大きなプロジェクトでは、このアクセス権管理が安全性や管理のしやすさの向上のため大切な考え方になってくる

補足

今回は説明のためにアクセス権を指定したが、今回の構造体であればアクセス権を定義しないで使っても全く問題はないので

GetやSetの関数を書くことにこだわる必要はそんなにない

使う側が確認しなかったり、デバッグをせずに壊れる可能性がある使い方をするほうがよっぽど大問題

終わりに

今回は構造体について説明してみました

次回以降の説明で大切になる要素を説明したので、わからなくなってしまったら見返してみてね

リンク

・メインページ