最初に学ぶプログラミング言語は、単にコンピュータサイエンスを学ぶだけであれば何を選んでもかまいません。
JavaScript、Python、Rubyなどの扱いやすいスクリプト系のプログラミング言語で十分でしょう。
しかし、実際にITエンジニアとして働く実務家になろうとするのであれば、Windows、Linux、組み込みなど、様々な種類のプロジェクトであっても対応できるほど汎用性が高く、すべてのプログラミング言語に共通する文法などの言語機能を持ったプログラミング言語である「C言語」を最初に習得すべきと言い切れます。
それほどC言語は、広く深い実践的な知識とテクニックを与えてくれます。
■ C言語はスクリプト言語を支える低レベルのプログラミング言語
プログラムは、CPUによって命令が実行されることで動作します。そのCPUに最も近いプログラミング言語がC言語なのです。
CPUが実行できる命令は、16進数で構成されたマシン語です。そのマシン語を書く人はいません。
マシン語を書くためのプログラミング言語には、アセンブラ言語がありますが、
いまでは、CPUやデバイスを直接制御する組込のブートローダ、割込ハンドラ、デバイスドライバなどでも、C言語さえ使えない箇所だけで使われます。
C言語とは言えば、CPUの構造に従ったアセンブラ言語によって、記述されています。そして、PHPやPythonなど、スクリプト形式のプログラミング言語本体は、C言語を使って書かれています。
プログラミング言語のヒエラルキーを図で示すと以下のようになります。
■ C言語の基本
C言語の基本機能は、文法、データ型、構造体、配列、ポインター、関数です。
・文法
①条件分岐
if文
「もし~ならば~する」の文脈に沿って、処理を実行する
switch/case文
特定のデータの値毎に、処理を実行する
②繰り返し
for文
ある回数分だけ、処理を繰り返す
while文
ある条件のときだけ、処理を繰り返す
③ジャンプ
goto文
無条件に、指定した場所の処理まで移動する
・データ型
①整数(short/int/long/long long型)
整数は、CPUのビット数(32ビット/64ビット)よってサイズが異なり、表現できる数値の範囲が変わります。それは、以下に示すようにOSに依存します。
OS | short | int | long | long long | ポインター | データモデル名 |
Windows(32ビット) Linux(32ビット) MAC OS/iOS(32ビット) Android(32ビット) | 16 | 32 | 32 | 64 | 32 | ILP32 |
Windows(64ビット) | 16 | 32 | 32 | 64 | 64 | LLP64 |
Linux(64ビット) MAC OS/iOS(64ビット) Android(64ビット) | 16 | 32 | 64 | 64 | 64 | LP64 |
引用:https://marycore.jp/prog/c-lang/data-type-ranges-and-bit-byte-sizes/
https://sgryjp.gitlab.io/posts/2016/2016-08-12/
②実数(float/double/long double型)
小数点も含めた数字は以下の実数を使います。C言語で扱われる実数の有効桁数には限りがあります。
float型:32ビット
double型:64ビット
long double型:128ビット
③文字/文字列(char型)
C言語では、一つの文字は8ビット(バイト)で表現されます。文字を繋げたものが文字列です。
文字・文字列は、人間がその意味を認識できるデータです。したがって、整数や実数のようにCPUで計算されることはありません。
現実の情報の大部分は、文字情報です。したがって、C言語でも文字列を扱うことが多くなります。しかし、C言語では、文字・文字列の扱いが充実しているとは言えません。特に、英語以外の日本語などの多言語のサポートは、後付けで無理矢理取り込まれており、プログラミングにかなりの不自由さ与えています。
・構造体(structure型)
各種データ型を組み合わせ、詰め合わせたものが構造体です。
構造体を定義する目的は、実際の情報は、マルチメディアであり、数字と文字列の集合で表したほうが、プログラミング上、扱いやすいからです。
たとえば、人というデータを構造体で定義すると、以下のように性別、年齢、名前、住所のデータの組み合わせで表現できます。人と言うデータを扱う場合、これらの塊として扱えれば、便利です。
struct {
int sex; // 性別(0:男、1:女)
int age; // 年齢
char name[128]; // 名前
char address[128]; // 住所
} person; // 人
・ポインター
ポインターを理解するには、CPUとメモリの関係を理解すること必要です。
CPUは、メモリの場所を示す「アドレス」を指し示すことで、メモリに格納されたデータ(実体)を読み書きします。
この「アドレス」のことをC言語ではポインターを呼びます。実体のデータは、ポインターを介して間接的にアクセスすることができます。
実体のデータをコピーしてしまえば、ポインターを使って間接的にアクセスする必要はなくなりますが、2つの致命的なデメリットが生じることになります。
一つは、更新による不整合が発生してしまうことです。コピーしたデータを更新しても、コピー元のデータは更新されません。
もう一つは、リソースの消費です。データをコピーする時間と、複製されたデータを格納するメモリが新たに必要になります。特に、貴重なメモリの消費は問題です。ポインターを使うことで、データの不整合とリソースの効率化を図ることができます。
一方で、ポインターのデメリットは、コードの複雑度が上がるため、バグが発生する確率が上がり、デバックの難易度が上がることです。
ポインター(=アドレス)という定義があることは、C言語がCPUの構造を反映したプログラミング言語であり、ハードウェアを制御する機能を備えていることを示しています。
ポインターを扱うことが、なぜ難しいのかというと、実データがいま見ているコードとは違うコードで生成されることになるからです。
果たして、今見ているポインターの先にある実データが存在するのか、想定しているデータなのかが保証されているわけではありません。実際にコードを実行して処理してみないとわからないのです。
プログラミング時点では、問題なくても、いざ実行してみるとエラーになったり、プログラムが強制停止(例外、クラッシュ)したり、あるいは、他のデータを全く違う値に書き換えて破壊してしてしまったりといったことが、十分に注意してプログラミングしていたとしても起こりえます。
・配列
同一のデータ型および構造体を複数使いたい場合、それらを列挙した配列として定義することができます。プログラムでは、複数のデータを一度に扱うことが多いため、配列は、頻繁に使われます。
前述したように、文字列も文字の配列ですが、最後尾にはNULL(0x00)を設定する必要があります。
・関数
数学でいう「関数=計算式」と同じように、ある値(入力値)を設定すると結果(出力値)が得られるように、ある特定の処理を実行するためのコードの塊をC言語でも関数と呼びます。
関数を呼び出す手順をコーリングシーケンスといいます。コーリングシーケンスには、関数名、引数(パラメータ)、戻り値(リターン値)を記載します。引数と戻り値にはデータ型、構造体を示します。
たとえば、人物情報を取得する関数のコーリングシーケンスは、以下のようになります。
/*************************************************************************
* 概要 :人物情報を取得する
* リターン値 : int 結果(0:正常、0以外:エラーコード)
* 引数 :
* int sex, 入力 : 性別(0:男、1:女)
* char *name, 入力:名前
* struct person *person 入出力:人物情報
**************************************************************************/
int GetPerson(
int sex, // 性別(0:男、1:女)
char *name, // 名前
struct person *person // 人物情報
);
プログラミングをするということは、関数を作ることであり、プログラムとは関数の集合体です。
プログラム設計とは、プログラムで実現する機能に必要となる関数を定義し、その処理を考えこと、そして、関数の組み合わせと手順を考えることです。
■ C言語の仕組み
C言語を使ったプログラムのファイル構成は以下となります。
①と②が、ソースコードと言われるものです。
①ソースファイル
C言語で書かれたコードの中、関数とその処理(ロジック)が記述されたテキスト形式のファイル。
拡張子は、”.c”。
②ヘッダファイル
C言語で書かれたコードの中、定数、構造体、関数定義(プロトタイプ宣言)などの型が記述されたテキスト形式のファイル。ソースファイルにインクルード(取り込み)されて、使用される。
拡張子は、”.h”。
③オブジェクトファイル
①と②を使って、コンパイラによってマシン語にコンパイル(翻訳)されたバイナリ形式のファイル。
個々のソースファイル毎に生成される。ただし、これだけでは実行できない。
拡張子は、”.o”。
④実行ファイル
③をリンカ―によって、リンク(連結)された一つのファイル。
(リンクとは、全てのオブジェクトファイルに、適正な実行アドレスを付与し、実行可能な状態にすること)
拡張子は、Windowsであれば、”.exe”、Linuxの場合は拡張子はなし。
これら生成過程を図で示すと、以下のようになります。
■ いかにしてプログラムは動くのか
実行ファイルが実行される手順は、以下のような流れとなります。
①OSが実行ファイルを読み込む(コンソール画面からの実行、ダブルクリックなどが起点)
②OSは、メモリ上に読み込んだコード(マシン語)とデータを配置する
③OSは、メモリに配置したコードの先頭へ移動(ジャンプ)する
④CPUは、メモリからコードを読み込み、メモリ上のデータにアクセスしながら実行を開始する
その過程で、LANやグラフィックスなど周辺デバイスにアクセスし、通信や画面表示などを行う
この過程は、どのプログラミング言語でも同様であり、最終的にはプログラムはマシン語まで変換された状態で実行されます。
■ まとめ
低級言語のアセンブラに対し、C言語は高級言語と呼ばれます。
その理由は、C言語には、プログラミングに単なる処理の手順を羅列するためのものではなく、人間が使う言語に沿った文法、データ型などを使って、情報を処理するための考え方である「概念」を表現することができるようにした点があげられます。
さらに、他の高級言語と違い、ポインターによってCPUの使うアドレスを表現できるため、アセンブラ言語が持つハードウェアへの操作性を併せ持つオールマイティなプログラミング言語と言えます。
ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい