プログラミング/共通知識

このページでは、プログラミングにおいて頻出である共通の知識を説明する。

概要編集

プログラミングはWindows(ウィンドウズ)、macOS(マック)、GNU/Linux(リナックス)、ChromeOS(クロームブック)、*BSD(ビーエスディー)どのOSでも、行うことができる。 スマートフォン向けのOS、iPhone(アイ フォーン) や Android(アンドロイド)などで行うこともできる。

※注釈:以下では、電子計算機を指す用語として「コンピュータ」、「コンピューター」が混在している場合があるが、どちらも同じ意味である。

「プログラミング」とは?編集

プログラム」はコンピュータにしてもらう指示をまとめたものです。「プログラミング」は、「プログラム」を作成することです。私たちはプログラムを作ってコンピュータに実行させることでコンピュータに仕事をしてもらいます。現代のコンピュータは、内部では0と1だけの2進数で動作しています[1]。2進数で表現されていることを特に「バイナリ」と呼びます。それに合わせて、指示は0と1のみで表現される「機械語」で与える必要があります。しかし機械語は直接読み書きすることは困難です。そこで、より私たちの話す言語に近い文法や単語からなる”記号”で指示を記述して、それをあとで2進数に訳して実行させるという方法が生まれました。この「翻訳する」作業を「コンパイル」と呼びます。

文字入力編集

プログラミングをするからには、文字の入力ができなくては始まらない。以下は、文字に関する概念を簡単に述べる。

バイナリファイルとテキストファイル編集

概要: バイナリファイルとテキストファイルは人間都合の呼びわけである。

コンピュータはHDD、SSDなどの記憶媒体にファイルを保存する。「テキストファイル」とは、文字として解釈することを想定されたファイルを指す。対となる概念として、「バイナリファイル」がある。Windowsではテキストファイルには.txtという拡張子を付けることが多い。プログラムを作るとき、拡張子は言語に応じたものを付けて区別する。

テキストエディタ編集

概要: テキストエディタは怖くない。

文字を入力するときは、専用のアプリを起動する。以下に不完全なOSに付属しているエディターのリストを示す:

  • Windows: メモ帳 (notepad.exe)
  • macOS: vi, emacs
  • GNU/Linux: nano

さらに、emacsやvim、Atom、VSCodeもテキストエディタと呼ばれる。エディタによっては、シンタックスハイライトと呼ばれる色分けをする機能や、折りたたみ機能など、特色ある機能を搭載している場合がある。テキストエディタのインストール方法については、ここでは取り扱わないので、各エディタのマニュアルを参照すること。

ワープロソフトは使えない編集

概要: マイクロソフト社のWord(ワード)のようなワープロソフトでは、テキスト以外に付属するデータがあるため、プログラミングには使えない。

ワープロソフトで保存されるのはバイナリファイルであることが非常に多い。ワープロソフトで文章を保存しても、文章がそのままテキストとして保存されるわけではない。そのファイルの拡張子を「.c」に書き換えてC言語として再解釈しようとしても、コンパイルエラーになってしまうだろう。なぜエラーになるかというと、ワープロソフトには、メタデータと呼ばれるフォントの種類、大きさ、色、位置関係の情報など、文字そのもの以外の情報もふくまれているからだ[2]

入力モード編集

概要: 大半のプログラミング言語において、ほとんどの記号、数字は、半角英数字で入力しなければならない。表示させたい文章などは、その限りではない。

プログラム中に出現する記号は、ほとんどの場合、半角英数字で入力する必要がある。大抵のOSでは直接入力モードに切り替える必要がある。OSによっては、半角モードと直接入力モードとは、べつのモードの場合がありますので、気をつけましょう。なお、Windows7では、半角英数が直接入力です。

print("おはよう")

というコードがあったとしたら、「print」「(」「"」は直接入力モードで入力します。「おはよう」を全角モードで入力します。そして、ふたつめの「"」「)」は直接入力モードで入力します。つまり、例外的に日本語表示をしたい部分だけを除いて、原則的に直接入力モードで、入力することになります。

拡張子編集

概要: ファイルの最後の「.」より後ろをw:拡張子と呼ぶ。ファイルの名前にはわかりやすくするために拡張子をつけておく。

拡張子(かくちょうし)はテキストエディタで保存する時つける必要がある。拡張子は、プログラミング言語の種類によって変わるため、それぞれのプログラミング言語についてのマニュアルを参照する。C言語で保存するには、「.c」を末尾につける。sampleという名前のファイルをC言語として保存する場合には、ファイル名をsample.cとする。

コマンドラインと慣れ親しむ編集

概要: キャラクターインターフェイスのみ用意されている場合は、コマンドラインで諸々の準備を行わなければならない。

  • Windowsの場合: cmdまたはpowershell
  • macOS場合: /bin/zsh[3]
  • GNU/Linuxの場合: /bin/bashが多い
  • FreeBSD,NetBSD,OpenBSDなどのBSD系Unixの場合: /bin/tcshほか

真っ黒な画面、白い文字。恐怖心を覚えるかもしれないが、避けては通れない道である。プログラミング言語によっては扱う必要がないかもしれない。パッケージマネージャーによるインストールなどはここでは扱わないので、各OSのマニュアルを参照。

  • コマンドラインから抜ける: exit

言語と言語処理系編集

コンピュータが認識できるのは機械語のみであることは先で述べました。しかしプログラミング言語は文法に沿った言語で書かれています。それらの書かれた文章をソースコードと呼びます。 プログラムを処理するためのソフトウェアを言語処理系と呼び、言語処理系はインタプリタコンパイラに大別されます。

インタープリター編集

インタープリターとは、プログラミング言語で書かれたソースコードや中間形式を逐次解釈しながら実行するプログラムのことです。 スクリプト言語と呼ばれる言語は、おおむねインタープリター方式を採用しています。 言語処理系の主要な実装がインタープリターなプログラミング言語をインタープリター型言語(Interpretive language)と呼びます。

インタープリター型言語には

などがあります。

手軽に書いてすぐ実行できるというメリットがある反面、プログラムの実行時に毎回解釈をする必要があるのでプログラムの実行速度はコンパイル方式のプログラミング言語に実行速度が劣る場合があります[4]。 インタープリター方式を採用した言語の処理系は、ソースコードを直接実行するのでプログラムを書換えると、即時に実行結果もそれに応じて変化します。

コンパイラ編集

ソースコードを予めに機械語(ネイティブコード)に翻訳し、機械語のファイルを実行するという方法もあります。 プログラムのソースコードコードを機械語に変換することを、コンパイルと言います。 コンパイルするためのソフトウェアのことをコンパイラといいます。 言語処理系の主要な実装がコンパイラなプログラミング言語をコンパイル型言語(Compiled language)と呼びます。 また、実行時コンパイラ(JIT; Just-In-Time Compiler)と区別するため、事前コンパイラ(AOT;Ahead-Of-Time)と呼ばれます。

コンパイル型言語には

などがあります。

コンパイル型言語では、ソースコードが書かれたファイルと、実行ファイルとは、別のファイルです。 そのためソースコードを変更してもコンパイルしなければ変更が反映されません。 コンパイル型言語の実行ファイルは、機械語で書かれています[5]。 コンパイル型言語のプログラムの実行では、機械語で書かれた実行ファイルをそのまま実行するので処理が高速です。 実行ファイルは、それぞれのハードウェアやオペレーティング・システムに合わせた形式になっています[6]。 Windowsをターゲットにした実行ファイルをGNU/Linuxにコピーしても実行できません[7]。 実行ファイルから元々のソースコードを取り出すこと (デコンパイル) は一般に困難です。 機械語にはそのハードウェア対する命令だけが書かれており、ソースコードは機械語には書かれていません[8]。 機械語に変換された実行ファイルは、配布するプログラムのソースコードを秘匿することが可能になる特徴があります。 プログラムのコードをコンパイルしたファイルを実行ファイルにまとめる前のファイルをオブジェクトファイル言います。 1つの実行ファイルが、複数のオブジェクトファイルから構成されることがあります。

     (コンパイル)       (リンク)
ソースコード1 ⇒ オブジェクトファイル1 ⇒ 実行ファイル
ソースコード2 ⇒ オブジェクトファイル2 ↑
        :             ↑
ソースコードn ⇒ オブジェクトファイルn ↑

という流れになります。

どちらでもない言語、両方できる言語編集

プログラミング言語をインタプリター言語とコンパイル言語に分けましたが、どちらにも属さないものや、どちらでも実現可能なものもあります。

中間コード型編集

ソースコードをコンパイルしてから中間コード・ファイルを生成し、実行は中間コード・インタプリタが行う形式があり、 この様な形式を中間コード型と呼びます。

中間コード型には

などがあります。

Java編集

Javaはソースコードを、Java仮想マシンが解釈できる中間言語 (Javaバイトコード) にコンパイルします。そして実行時に、その中間言語を読み込みそれを実行するという仕組みです(中間コード・インタプリタ)。中間言語ファイルは機械語から独立しているため、どのハードウェアでも使うことができます。かわりにユーザーは、Java中間言語を実行するソフトウェア (JRE; Java Runtime Environment) をインストールします。そして、そのJavaのランタイムは、Windows、macOS、GNU/Linux系列といったそれぞれのOSごとで動作するように開発・維持されています。ユーザーから見れば、Javaのように中間言語を生成するプログラミング言語は、どのOSにも依存せず動作するので理想的なように見えます。しかし、ユーザーから見て統一的なAPIを提供しつつ、統一的なAPIとそれぞれのOSの違いを吸収する部分を実装することは非常に手間がかかります。

JVMを利用するJava以外の言語、Groovy, Scala, Kotlin, Clojureなども登場しています。

両方できる言語編集

また、コンパイルして実行することもインタプリタで実行も両方できる場合がある。Python、Go言語、Haskellは、その例です。

例外編集

コンパイル型言語を逐次実行、あるいはインタプリタ型の言語をコンパイルして使用する場合
コンパイル型言語に分類されるC言語のソースコードをインタプリタで逐次実行することがある。
逆に、インタプリタ型言語に分類されるのBASICのソースコードをBASICコンパイラでコンパイルし生成された実行ファイルを実行することもある。

この様に、言語処理系の主要な実装があるいは多くの場合は最初の実装が、インタプリタなのかコンパイラなのかで分類しているので、例外が生じる余地があります。

字句解析器・構文解析器編集

字句解析器編集

ソースコードは通常の文字列ですが、まずは、空白での区切りや既知のキーワードあるいは区切子に鑑み、文法上の最小単位の列に還元します。 この文法上の最小単位をトークンと呼びます。 トークンを切り出すプログラムのことを字句解析器(じくかいせきき;lexical analyzer レキシカルアナライザー)あるいはトークナイザー(Tokenizer)と呼びます。

構文解析器編集

字句解析器の出力は、トークンの羅列(トークン列)です。 このトークン列を先頭から読出し、プログラミング言語の構文に当てはまるか、パターンマッチングを行い、一致したパターンに従い内部表現(構文木など)に変換します。 このようなプログラムのことを、トークン列から構文を解析するという意味で、構文解析器(こうぶんかいしゃくき;parser パーサー)と呼びます。 構文解析にあたって、解析中のトークン列の注目している部分が、2つ以上の構文にマッチすることがあります(構文規の衝突;例えば懸垂if)。 この様な場合は、優先順位や結合方向を文法で規定することにより、一意にマッチする構文が定まるよう、実装上の工夫が必要です。

字句解析と構文解析を別々に行うことが可能なプリグラミング言語もありますが、多くのプログラミング言語では(文法に曖昧さがあったり、字句に対し意味論が重複している[9]などの理由で)字句解析と構文解析は連携し実装されています。

文法編集

代入編集

注釈: a = a + 1が何を指すかご存知だろうか。aが変数、 x = yが変数xに式yの評価結果を代入していることが理解できるのであればこの文章は読み飛ばしても良い。

プログラミングと数学では、=が指す意味が違う。数学では、=は等号であり とすることで、  が等価であることを意味する[10]。プログラミングにおいてa = bは変数aに式bの評価結果を代入する。たとえば、a = a + 1で、aの値が2だったとすると、a = 2 + 1となり、2 + 1の評価結果3aに代入される。

変数編集

なお、上記の説明で、当然のように「変数」という言葉を用いたが、この「変数」という用語も、数学とは扱いかたが微妙に違うので、気をつける必要がある。 変数名の命名規則については、それぞれのプログラミング言語のマニュアルを参照すること。 また、なお、たいていの言語では、大文字・小文字を区別する(case-sensitive)[11]。 C言語で例を示す:

例1
a = 2;
a = A + 1;

以上のプログラムはエラーになる。aAは区別され、Aが定義されていないためである。 変数aを1増やしたいのであれば、例2のようにする。

例2
a = 2;
a = a + 1;

実行すれば、aの値は3になる。

静的型付け言語と動的型付け言語
プログラミング言語は、静的型付け言語と動的型付け言語に大別されます。両者の間で、代入や変数の意味論が異なるので明確に区別する必要があります。
静的型付け言語
具体例
Fortran, COBOL, C言語, C++, Java, Go, Rust
特徴
変数は型を持つ
代入は、変数と結びついた記憶領域への右辺値のコピー
動的型付け言語
具体例
Lisp, JavaScript, Python, Ruby
特徴
変数に型はなく、変数に束縛された値(=オブジェクト, =インスタンス)が型を持つ
代入は、変数への値の束縛

BASICのような変数名に型情報を持った言語や、関数型言語の一部のように変数そのものを持たない言語もあります。

プログラミング言語の学習において、その言語のパラダイムにおける型システム・変数システム(オブジェクトシステム)の理解は初学時の重要な要素です。


実行順序編集

単文は出現順序が先の方から順に実行されることがほとんどである(逐次実行[12])。(C言語では)式の後に; (セミコロン) を後置すると文(式文)となる。例2で示したプログラムなら、a = 2;のあとに、a = a + 1;が実行される。

文や式の様な構文要素の分類は、プログラミング言語によって異なる。

数値編集

ソースコードで記述する整数リテラル、及び小数リテラルは、特に指定をしないかぎり、10進数である。整数と、(ほとんどの場合、IEEE 754に準拠した) 有限のケタの小数が、普通のプログラミング言語では使える。分数や平方根(  など)などは、関数として用意されている場合でも、評価結果が近似される。また、小数も精度以下の部分は近似して表されます。

もし   に近似されたなら、コンピュータ内部では、 ではなく、 という値として表現されています。上記のように、本来なら数学的には無限のケタの平方根などの無理数を有限ケタの小数に近似してしまうため、誤差が発生する。このような、無限小数を有限小数に近似したために誤差の発生する現象のことを浮動小数点数による誤差という。

過去の編集で、浮動小数点数による誤差ケタ落ちとしていましたが、桁落ちとは、丸め誤差を含む非常に近い大きさの小数同士で減算を行ったときに、有効数字が減る現象のことを言い有限の仮数部と指数部で表すことによる誤差とは違う概念です。また一般に浮動小数点数は2進数が採用されているので、十進数では有限桁数で表現できても浮動小数点数では循環小数になることがあります(例えば、 0.110 = 0.000110011001100…2)。

関連項目編集

脚注編集

  1. ^ フラッシュメモリーのMLC/TLCに代表されるw:多値論理など、特殊なアーキテクチャを採用しているコンピューターを除く
  2. ^ 実は多くのワープロソフトではテキストファイルを保存する方法が用意されており、それで保存すればプログラミングもできないこともありません。ただしワープロソフトはプログラミングを意図した設計になっていないので、ワープロソフトでやるメリットはほとんどありません。
  3. ^ macOS 10.15 Catalina(2019) からディフォルログインシェルが、それまでの bash から zsh に変わった。
  4. ^ インタープリターは実行時に「どの部分が多く実行されたか?」「分岐命令でどちらに多く分岐したか?」などの実行時統計情報を容易に手に入れることができ、これらに基づき実行時コンパイラ(JIT)による最適化が可能となります。よって、一概にインタープリター方式がコンパイル方式より実行速度が劣るとは言えません。
  5. ^ UCSD-PascalのP-Codeや、JavaのByte-codeの様な中間コードを生成し、中間コード・インタープリタが実行する言語処理系もあります。
  6. ^ 異なるハードウェアの実行ファイルは、通常は仮想機械環境を使わない限り実行できません。
  7. ^ 同じハードウェアでも異なったOSで相互に実行ファイルが実行できない理由は、いくつかありますが、実行ファイルの形式の違いとOSの提供するシステムコールの違いが主なもので、この2つを克服したWine(GNU/LinuxでWindowsの実行ファイルを実行可能にする環境)やWSL(WindowsでGNU/Linuxの実行ファイルを実行可能にする環境)では異なったOSの実行ファイルの実行を実現しています。
  8. ^ ただし、デバッグや動的リンクの為のシンボルは実行ファイルに含まれている場合もあり、デコンパイルの難易度を下げます。
  9. ^ 例えば、C++では、キャストと関数呼出しあるいは初期化の構文に衝突があり、型や関数の定義状況との照会を行わないと、構文の特定ができません。
  10. ^ 数学においては、=を等式ではなく代入に用いることもあり、コンテキストによって読み分けられる。
  11. ^ 比較的古くからある言語では、大文字・小文字を区別しない傾向にあります。具体的には、FortranCOBOLLispALGOLBASICは大文字・小文字を区別しません。理由は1つではありませんが、有力な理由の1つに小文字がコードがコード化されたASCIIが制定される1963年より前、あるいは同時期に言語設計と言語処理系の実装が行われたから、と考えられます。むしろC言語(1972)が比較的古い言語であるにもかかわらず小文字を区別していることが特異的といえます。
  12. ^ 現実のプロセッサーは、主に実行効率のために、投機実行やアウトオブオーダー実行などで逐次ではなく並列で、またインストラクションの順序を組替えて実行している。しかし、プログラマーから観た意味論は変更しない範囲で行われる(一部のRISCプロセッサーのディレイスロットの様な例外はある)。