桐生あんずです

日常やプログラミングについて書いています。

「苦しんで覚えるC言語」でC言語を入門してみた

桐生あんずです。今年のRubyKaigiに行った際に、発表の中でC言語の話がたくさん登場し「これ、C言語を勉強した方が良いことが多いのでは…」と思い立って「苦しんで覚えるC言語」という本を買って読んでいました。

苦しんで覚えるC言語

苦しんで覚えるC言語

 今までRubyしかまともに書いたことがなかったのですが(最近になってJavaには触ってみた)、C言語を触ってみて色々発見があったので書いていきます。

インタプリタ言語とコンパイル言語について

インタプリタ」と「コンパイル」という言葉は実際に聞いたことがあり、それらの意味をちょっと調べてみたこともありましたが、コンパイル言語(C言語)を触る自体は今回が初めてでした。

この本を読みながらC言語を実際に触っていくと、C言語は「コンパイラ」というC言語で書かれた文字列ファイルをマシン語に翻訳するソフトを使い、最終的に翻訳した機械語プログラムがリンカというソフトで結合(リンク)されることで、マシン語のデータが実行可能ファイルとなりアプリケーションとして実行できるという流れがあることを知りました。

このコンパイラの仕組みによってC言語のプログラムがより高速に動作するようにマシン語に翻訳されていくとのことです。*1

また、Rubyインタプリタの仕組みを利用しています。インタプリタコンパイラとは違って同時翻訳を行いすぐに実行することができます。インタプリタは速度が低速ではありますが、柔軟な構成が可能とのこと。(P46から参照)

(そして、RubyKaigiでは、コンパイル言語であることで高速なC言語よりもRubyが高速に動作するように実装を考えていた人々がいた)

実際にXcodeを使ってコンパイルしつつC言語のコードを動かしていましたがRubyとはかなり違ったやり方で新感覚でした。ターミナルを使ってgccコマンドを使ってコンパイルすることもしてみましたが、こんな手間があるのか…!ということに驚き。

・main関数は特別

Rubyを触っていると本当にカルチャーショックな話なんですが、C言語はmain関数が一番先に実行されるという決まりがあります。

#include <studio. h>

int main(void) 
{
  printf("Hello World");
  return 0;
}

こういう感じのやつです。このmain関数を軸にコードは展開されていくのですが、他の関数を呼び出す際には、プロトタイプ宣言*2しておく必要があったりなどこれらに関しても普段Rubyを書いている身からするとびっくりな出来事でした。

・静的型付けであること

これらに関しても、Rubyは動的型付け*3なので、型宣言をせずともコードを書くことができますが、C言語は静的型付け*4なので毎回変数や関数の戻り値や引数に型宣言をすることが求められます。ここもRubyではあまり出くわさないシチュエーションですね。

ここの部分の文章を書く際に動的型付けと静的型付けについて書かれた記事をいくつか見て回りましたが、どちらかが良いと断言できる話ではないと思うので私レベルの入門者がどう書くべきなのかめちゃくちゃ難しい…。
ただ、動的型付けだと書きやすいケースもあるし、静的型付けだと安心なコード設計がしやすい、と色々なメリットやデメリットの話を展開することができて本当に奥が深い話だなと思います。

RubyKaigiでも型付けの話はMatzのKey Noteで話題になっていましたね。ふと思い出して探していたらQiitaの記事でレポートされている方がいた。

静的型付け言語(typescript等)が巷では流行っているが、Rubyでの型付けについてどう思うか?という質問への回答が興味深かった。
matz曰く、静的型付けのメリット(流行っている理由)は理解しているつもり。ただし、Rubyでは型宣言できるようにする予定はないと答えた。
なぜならコンパイラがもっともっと頭がよくなって行ってコンパイル時に型を予測してくれる未来が見えるから。
もしかしたら、2040には静的型付け言語はダサい、古いと言われているかもしれない。
Rubykaigi2018 - Matz keynoteまとめ より引用

・ポインタ変数という存在

「ポインタ」という概念を知ったときもRubyでは知ることのなかった話だったので新鮮な感覚で読み進めていました。このポインタについて説明されている15章では、最初に変数とメモリの関係性についても述べています。

一言で言ってしまうと全ての変数はメモリに作られていて、番号をつけて区別しているとのことです。これも今まで意識したことのない話で、目から鱗でした。

もしかしたら基本情報技術者試験のテキストでも見たかもしれないけど、この本ではメモリの構造についての解説がわかりやすくなされていてよかったです。(メモリは巨大な1列ロッカーであり、オンとオフで管理されているという例え話がすごいわかりやすかった)

本題のポインタ変数ですが、ポインタ型*5で宣言された実際の変数です。この変数には、その元となった型の変数のアドレスを自由に代入できます。
変数のアドレスの値を記憶することができるもので、記憶しているアドレスのメモリを読んだり書き換えたりすることができます。
ここで一気にメモリやアドレスなどの概念を一気に意識することになるので、理解するまでに何回も読み返していました…。

使い方としては、「ショートカット」のようなものとのこと。
詳しく掘り下げて行くと、ポインタ変数に実際に存在する変数のアドレスを記憶しておけば、そのポインタ変数が使える場所であれば、元の変数が使えない場所であってもポインタ変数を通常変数モードに切り替えれば、元の変数と同じく使うことができるとのこと。

つまりは必要なデータを扱うための便利ショートカットツールというような扱いっぽい。
これらに関しては本当に知らなかったのでびびりました。調べて行くと、「リスト構造*6」なんてものがあったりと(よく探してみると基本情報技術者試験でもこれに関する問題出てますね)、もっと深めていくと良さそうな感じがあります。

まとめ

構造体についてやmalloc関数とfree関数についても掘り下げていきたいところなのですが、文字数が無限に増えていきそうなのでここで一旦止めておきます。最近作った技術ブログでゆるっと補足するかもしれない。

最終的に何を書きたかったかというと、C言語の実態を知ることで、Rubyだけでは知ることが難しかったプログラミング言語に関する基礎的な概念に触れることができたということです。また、Rubyの書きやすさを改めて思い知らされました。どこかのエントリで似たようなことを書いたかもしれないけど、他言語に触ってみることでRubyがいかに初心者が触りやすい言語であるかをちょっと知ることができました。

また、Rubyの学習に関しては「プロを目指す人のためのRuby入門~言語仕様からテスト駆動開発デバッグ技法まで~」がすごくお世話になりました。これを読むとRubyの基礎がじっくり学べます。Railsをやっている人向け。


ソフトウェア開発をしていく中では、C言語に実際に触れることはなかなか少ないと思うのですが、新しい言語を習得していく中でC言語を触った経験があると学習コストが低くなっていくのではと感じました。直接的に役立つことは少ないかもしれませんが、知って損はないのかもというのが今の感触です。今後何か役立つことがあってほしい。

C言語入門が終わったところで、次は家にある「新・明解C言語で学ぶアルゴリズムとデータ構造」を読むとアルゴリズムについて深く学べて良さそうだなという気持ちがしているので、他の読みたい本と並行しつつ読んでいこうと思います。

もしくは、今サークルの活動でゲーム開発に関わろうとしているので、C#Javaなどを改めて入門してみるのも楽しそうだなと感じています。
という感じに、今後も興味がある分野に関してどんどん掘り下げていきたいです。

*1:C言語にもインタプリタ式の環境はあるとのこと。

*2:あらかじめ先頭で関数の形を宣言しておくことで、ほかのすべての関数からその関数を使えるようにすること

*3:プログラミング言語で書かれたプログラムにおいて、変数や、サブルーチンの引数や返り値などの値について、その型を、コンパイル時などそのプログラムの実行よりも前にあらかじめ決めるということをせず、実行時の実際の値による、という型システムの性質のことであること。(( 動的型付け - Wikipedia より引用

*4:プログラミング言語で書かれたプログラムにおいて、変数や、サブルーチンの引数や返り値などの値について、その型が、コンパイル時など、そのプログラムの実行よりも前にあらかじめ決められている、という型システムの性質のことである。 静的型付け - Wikipediaより引用

*5:アドレスを記憶する変数の型

*6:ポインタ型(アドレス指定型)のデータをつないで、全体を操作できるようにしたデータ構造