先日は、
にて、C言語の環境構築とターミナルを使った処理について書きました。
コンピューターも自動処理をする為のハードウェアになりま菅、歴史を紐解くと紀元前には水を使ったソリューションが存在しているので、特定のアルゴリズムを実装したハードウェアを用意して水の流れを作業に必要な動作変換して水の力を使ってそれを行うようなものが損刺し居ていました。この場合、抵抗を用意してその抵抗によって生じる運動エネルギーで別の運動を発生させて動かすような仕組みになていますが、これが、入力部分になります。そして、目的の作業が出力になりますが、この 入力 → 出力 の部分間に変換や目的の挙動になる法則性を実装する必要があるので、 判定 や 処理 を実装することになります。その為、動きを作る場合には、
■ 入力 : センサー
■ 判定 : コントローラー
■ 出力 : アクチュエーター
が必要になるわけですが、古代のソリューションでも入力を水の力で行い、判定部分を挙動を実装した構造物で実装し、作業を行うための出力部歩の構造物を作ることで、自動処理が行えるようになっていました。こうした、単一の機材に単一の動作を実装する仕組みは、カラクリやオートマタも同様ですが、特定の挙動になるハードウェアは仕組みを作ればその通りに動くので、一般的な機械の制作はこの考え方で行うことになります。
これが単一の作業を行えるものになりますが、制御には音楽のように譜面のようにデータで異なる曲を実行できるものもありますが、この場合、特定の機材が音を奏でるとい条件で考えると実行環境を用意すればデータの差し替えだけで異なる音楽を再生できるようになります。この仕組みはカリヨンやパイプオルガンなどで使用されますが、コレを個人レベルで楽しめるものにしたのが、オルゴールになります。オルゴールも工芸品なので、オートマタと連動したものがありますが、動作の制御を法則性で行っているものもあるので、かなり複雑な動きをするものも存在しますから、時計台のような動きをするものもあります。これがデータの夜制御なので パターン制御 になりますが、ピンや穴の状態で動作する仕組みなので二値のデータの状態で単一の音階の除隊を制御する仕組みになっており、これが音階分だけ並列化されているので、音楽を奏でることが出来るようになっています。この構造を手回しで行う手回しオルガンもありますが、この楽器で使用する譜面はDAWやMIDIシーケンサで使用するピアノロールと同じ構造になっています。流石に、PCやCCは存在しませんが譜面の構造などや音階と音価の制御方法は同じです。
こうした二値のデータで制御をする仕組みを産業に応用したのが自動織機になりますが、その後、データを用意してパターン通りに動くものではなく、機械で計算をする機材が登場することになりますが、歯車で計算を行うものからスタートしたハードウェアは真空管や電磁石などを経て、電子パーツで動くようになります。こうした構造も集積化が進むと小型化が進み気軽に計算ができるようになりますが、計算は入力した内容を計算するだけですから、このハードウェアでは 判断 をする能力を有していませんが、機械に判断をさせるような仕組みをアナログではなくデジタルの内部処理で行えるようにしたものがコンピューターになります。
完全なアナログの機材でもカウンターの制御は出来るので、昭和初期の機械でも数値の指定で処理を繰り返すようなループ処理とカウンターの数値で止まる条件分岐を実装し、そのループの間に工程に基づいて動作する逐次処理を行うような構造のものは存在しているわけですが、こうした制御を実装したコードで処理ができれば、自動織機のようにデータの入れ替えをするだけで異なる処理が出来るようになります。
自動織機では、コントローラー部分はハードウェアで構築しているので、処理その物はハードウェア依存の状態になっていましたが、コンピューターではプログラミングを行うことで、この 判断 などもデータのように差し替えて使用できるようにする仕組みになっています。
機械の動作はオルゴールと同じなので、基本的にな日で動作しているので、これを使うためにはこのデータを格納する必要がりますが、これをまとめて十六進数にして特定の場所に保存するような仕組みにした場合、 住所とデータの値だけで処理を実装する ことになりますから、かなり敷居の高いものになります。これを解消するために機械ごと1対1でやり取りが出来るアセンブリ言語が登場しますが、これもレジスタにデータを書き込んで読み書きしたりそこに判定やループなどを入れて処理をするというものですから、処理に使用するものは少ないのですが、なぜその挙動になるのかはコードを見ただけでは全く理解できません。その為、人に解る体型で記述したプログラミング言語として高水準言語のFortrunが登場するわけですが、1972年にAT&T ベル研究所によってC言語が開発されます。この言語はB言語を元に開発されたもののようですが、コード内にアセンブリ言語の記述を行えるインラインアセンブリと言う機能も実装されているので、高水準言語の記述だけでなくアセンブリのコードを包含して実行することも出来るようになっています。
C言語はコンパイル型言語なので、コンパイラなどの実行ファイルを生成する為のソフトウェアをインストールスつ必要がありますが、C言語もネイティブコンパイラなので、CPUのアーキテクチャが異なると命令セットが異なるので違う環境ではバイナリが動きませんし、OSが異なると処理自体が異なるので、全く違うバイナリが出来上がります。その為、使用する環境に合わせたビルドが出来る環境を用意する必要があります。
コーディング環境と実行環境が同じであれば問題がないのですが、そうでない場合には、クロスコンパイルをする必要があります。
Linux環境では、ターミナルで アプリケーション名 --version と入力するだけでインストールの状態を確認できるのですが、インストール済みであれば、バージョンの表記がされ、そうでない場合にはインストールサれていないメッセージがでてインストールの方法が表示されます。
Linuxのターミナルでは、通常はBASHが動作するようになっていますが、 vi コマンド を使うとターミナル内でテキストエディタを使用することが出来ます。
のようなコマンドを実行すると、
のような画面いなりますが、現在のターミナルでは、
のように2つに分割してテキストエディタとBASHが動く状態にしたり、継続して動くコンソールアプリを作ってごカス時の負荷を確認するために、ターミナル側のウインドウを上下に分割してHTOPを表示することも出来ます。
HTOPは現在のCPUとメモリーの仕様状況をリアルタイムで確認できるツールになりますが、この表示もターミナル内で行えるので
のような表示で状態を確認することが出来るようになっています。
このようにLinux環境ではターミナルを使うとコーディングとでバックの表示を一つのウインドウ内で行えるようになっていますが、タブも使用できるので異なるターミナルを開いて別の処理をすることも出来るようになっています。
OSによる違い
C言語はOSによってビルド後に完成する実行ファイルが異なるのですが、
■ a.out : LinuxやMAC
■ a.exe : WINDOWS
のように異なるファイルが出来上がります。また、Linuxではそのままgccやg++が動作しますが、WINDOWS環境ではLinuxコマンドが動作しないとC言語やC++が動作しませんから、それを実行する環境として
■ Cygwin
■ MinGW
などをインストールして環境を構築する必要があります。
プログラミング言語とコードの記述
プログラミング言語デコードを記述する際には、使用するプログラミング言語の仕様に合わせた構文が存在するので、それに準じた記述を行うことになります。どのプログラミング言語を使う場合でも処理を行う時の条件として、
■ 使用するものは事前に準備する
■ 工程順に処理を行う
ことになります。処理全体を見た場合、処理自体は個別の処理の集まりで構成されていますから、この個別の処理が目的の結果になるような工程で並んでいます。オブジェクト志向のコーディングだとクラス図を使ったクラス同士の関係性で成立しているので、クラス図を見ないと何をしているのかイメージしづらい場合がありますが、手続き型の処理や小さな構造の処理単位で見た場合でも処理には必ず工程が存在します。
その為、 処理の流れを最初に考える 必要がありますが、処理を行うためには構成要素である部品が必要になりますが、計算をする場合に、定数の結果を導き出すには定数項が必要になりますから、数字の記述がされていて確定した値が必要になります。プログラミング言語でも同様に 値 を使う際には、値を用意する必要がありますし、使用する物があった場合には事前に読み込んでおく必要があります。
この構造は、大半の言語でそうなっているのですが、言語によって仕様が違っています。
例えば、入門用のプロググラミング言語のBASICインタプリタでは外部ライブラリの参照が登場することはありませんから、変数の宣言とコードの記述で処理が行えます。Pythonでもそういった記述は行えますが、その方法だと組み込み関数しか使用できないので、機能を使うためにはインストール直後から使用可能な標準ライブラリを使用することになります。
Pythonの場合、組み込み関数だと特に記述もなくコードを掻いて実行できますが、C言語の場合だと、処理を行うための機能を読み込まないとコードの実行が出来ないので、標準出力である モニターへの文字の表示 を行うだけでも組み込み関数を読み込む必要があります。
そして、基本構造として 関数 を用意してその関数内の処理を実行すると言う仕組みになっていますから、Pythonと比較すると表示を行うだけでも少し厳格な記述になっています。
この仕様はC++も同様ですが、JAVAはオブジェクト指向の開発が基本なので、UMLを使ったクラス図を作ってコードを書くとそのままコードの日永型が出来て、そのクラス単位でコードを追加していくだけでプログラムを作ることが出来る(これは、オブジェクト指向全般でそうなっています。)ようになっているのですが、この仕様で考えると、便宜上、処理を行う構造体は関数ではなくクラスを使う音になります。
このようにプログラミング言語では、個別の仕様が存在するので、それに準じた構造にする必要がありますが、ほとんどの言語で、プログラミング言語を機械語に翻訳して実行できる環境を用意すると、
■ 組み込み関数
■ 標準ライブラリ
が同時にインストールされるので、この中から必要な処理を行う物を呼び出して使用することが出来るようになっています。
関数の仕組み
C言語では関数を使って処理を実装しますが、関数の構造は高校の数学の合成関数で使用する f(x) = 変数xの関数 と同じものになります。この構造では、
■ 処理の実装 : f(x) = x
■ 解の取得 : f(1)
の様な形で行います。これは、中学校の数学の関数だと y = x と全く同じものになりますが、f(1)は、変数xに対して1を代入した状態になります。コレが関数の構造になりますが、プログラミング言語で関数を使う場合には、この構造をそのまま使う事になります。
関数部分を見てみると、 関数名(変数) = 処理の内容 となっていますが、関数の場合、関数の宣言と処理は分けて記述するので、構造としては
関数名(変数)
処理の内容
のような構造になります。これだと別の処理のようになるので、プログラミング言語では、処理の中に包含する内容をブロックで管理することが出来るようになっています。Pythonの場合だと、
関数名(変数) :
処理の内容
のような感じで、 : を使うとブロックが指定されるのですが、C言語などの場合、ブロックの表記は {} の中に記述することになります。その為、関数の構造は、
関数名(変数) {
処理の内容
}
のようになります。ただし、
関数名(変数) {
処理の内容
処理の内容
}
のように複数の処理が含まれる場合、
関数名(変数) {
処理の内容処理の内容
}
と区別が出来ませんから、処理単位で区別する必要があります。その為、C言語では、関数内の処理については、
関数名(変数) {
処理の内容;
処理の内容;
}
のように 【 ; 】 で区切るようになっています。この構造を見ると、数学の合成関数で使用する構造と告示していてその拡張によって成立している事が確認できると思いますが、関数の場合、関数で読み込んで使用する数値のことを 【 引数(ひきすう) 】 と言います。その為、先程の構造は、
関数名(引数) {
処理の内容;
処理の内容;
}
という形になります。
関数の型
ここまでで基本の構造は完成するのですが、厳格な言語の場合だと関数名を指定した際にはその変数の型を指定する必要があります。C言語の仕様では、 【 省略するとintになる 】 というものがありますが、基本的には、型を記述することになります。仮に、この時の型をintとすると、
関数名 int (引数) {
処理の内容;
処理の内容;
}
のようになります。これはデータの型になりますが、変数の宣言をする際にも型の宣言が必要になります。
引数
このように関数では、型を指定してから処理を実装しますが、関数と同じで、数値を使用する際には引数に値を代入する必要があります。ただし、表示を行う場合のように 数値やデータを参照しない条件 もあります。この時に 空の型 である void を使用します。なので、表示を行うような条件だと、引数がないのでvoidになりますから、
関数名 int (void) {
処理の内容;
処理の内容;
}
の様な構造になります。
戻り値
先程までの記述で基本的な関数の構造はできましたから、処理を実装して処理其の物に問題がなければ関数内での処理はただし奥行えることになります。ただし、 関数内の値は関数内でしか使用できない ので外部参照をすることが出来ません。そのため、関数内での処理の結果を使用する際には、それを 戻り値(もどりち) として出力する必要があります。これは、関数内部で生成された変数でも使用することになりますが、表示のように変数の値を参照しない条件でも必要になります。
この時に return を使って戻り地を取得することになります。例えば、関数内で数値や値などの参照する状態
関数名 int (void) {
処理の内容;
return 戻り値;
}
のようになりますが、C言語の場合、表示をするだけの状態のように変数参照が存在しない状態だと、
関数名 int (void) {
処理の内容;
return 0;
}
のように return 0 を用います。
Pythonの場合だと、関数で生成した引数を戻り値に格納して参照して使用するので、
関数名(引数):
処理の内容
return 戻り値
のようになりますが、引数も戻り値もなく処理をするだけだと
関数名():
処理の内容
のように省略されます。この辺りがプログラミング言語による記述の違いになりますが、C言語の場合、
【 表示などの場合 】
・ 引 数 : viod
・ 戻り値 : 0
【 戻り値がある場合 】
・ 引 数 : 引数
・ 戻り値 : 戻り値
を指定することになります。例えば、
・ 引 数 : x
・ 戻り値 : y
の場合だと、
関数名 int (x) {
処理の内容;
return y;
}
の様な形になります。
関数の実行
どのプログラミング言語も同じですが、基本的に関数は オブジェクト なので、変数の中に格納できます。
その為、 実行結果を変数に格納して使用する 使い方をします。この場合、戻り値を変数に格納することになりますが、関数は、 引数を参照して関数を実行する仕組み ですから、この記述の際に引数も指定することになります。
つまり、 f(1) のような結果が確定するような値を格納した状態の構造物を変数に代入することになります。
そのため、 型 変数名 = 関数名(引数) のような形で関数を実行することになります。この状態で数値を使うとしてintを指定して、関数名がf1とした場合、
int 変数名 = fa(引数に代入する値)
と言う形で関数を実行することが出来ます。この構造は関数が使用できる殆どのプログラミング言語で共通していますが、基本的な構造は高校の数学で登場する合成関数の仕組みと同じです。
その為、C言語では、
【 関数の基本構造 】
関数名 型 (引数) {
処理の内容;
return 戻り値;
}
【 関数の実行 】
型 変数名 = 関数名(引数に代入する値)
で行うことになります。この方法だと、戻り値は変数の中に格納するので、変数を処理の中に組み込めば関数の実行結果を処理の中で使用することが出来るようになります。
C言語とmain関数
前述のようにC言語に限らず関数を使うプログラミング言語では、
■ 関数の実装
■ 関数の実行(変数に代入後に処理)
のような流れになりますが、C言語やC++の Hello,world! のコードを見ると関数の実行をする変数への代入や関数の呼び出しのコードが存在していないと思います。コードの内容を先程の状態で対比してみると、 main と言う関数名のものだけ存在しており、処理はその中に記述されたものだけになっています。
pythonで同じことを行うと、関数の定義だけで終わってしまうのですが、C言語ではmain関数は特別な意味を持つ関数なので、コレだけでコードが成立するようになっています。
main関数は、 記述された内部の処理を実行できる関数 なので、Pythonで print(’Hello, world!’) の様な記述を直接書くのと同じ状態を作る際に、この関数を宣言する必要があります。つまり、 コードの実行部分がmain関数 になります。そのため、c言語でコードを書く場合には、
型 main (引数) {
処理の内容;
return 戻り値;
}
の構造を用意して、この main()関数 の中に処理を実装することでコードの実行が出来るようになります。
マイコンの制御をする際にスケッチを書いてマイコンへコードを送ることになりますが、この時に処理が実行される部分もmain()関数の部分になります。
I/O周りの設定
ここまでで処理を実行するためのmain()関数の意味合いと、その構造について紹介しましたが、この状態だと処理が実行されません。これは、main関数の記述だけだと入出力を行うデバイスへの処理を実行する状態になっていないためです。
C言語では、表示な入力を扱う際に 組み込み関数 から stdio.h という ヘッダーファイル を読み込む必要がありますが、これはPythonの標準ライブラリを参照するのと同じ処理になります。
Pythonでは組み込み関数はそのままinmportなしで使用できますが、C言語は、 使う道具は最初に用意する という内容が厳密なので、
■ 標準入力
■ 標準出力
に関しても外部参照をしないと実行できないようになっています。使用する道具を最初に揃えて実行するというのはこうした部分も含まれますが、一般的な言語だとこうした読み込みが発生する場合が多いです。特に、JAVAやC#だといきなりクラスを使うので、先に読み込まないと動作しない条件は多いのですが、Pythonでコンソールアプリを作る場合でも数学的な処理をするだけで標準ライブラリを読み込みますから、こうした考え方は、現在の言語では一般的なものになっています。
Pythonでは、標準ライブラリやユーザー関数を作って読み込む際にはimportを使いますが、C言語では、【 include 】 を使用します。その為、表示などを行う際には、コードの最初に 【 include <stdios.h> 】 と言う記述を行うことになります。その為、C言語のコードを書く時の雛形は
#include <stdio.h>
型 main (引数) {
処理の内容;
return 戻り値;
}
と言う形になります。