要約
- C、C++、C#という順番はなかなか良かった
- とはいえ、趣味人ならC#とかPythonから入ってもいいんじゃないかな
本文
新卒で入った会社の研修で、C、C++、C#とやってきた。
はじめて触る言語として、C、C++、C#という順番はなかなか良かったように思ったので、書き記しておくことにする。
前提
とっても小さいところです
弊社は地方の中小企業だ。
片手で数えられるというほどではないが、まあ、10人くらいいたら片手で数えられるくらいの規模である。
Cの組み込み系の仕事があり、MFCの仕事もいまだあり(つまり、C++)、メインの業務のソフトウェアはC#であり、というような感じである。
誰にどういう業務が当たるかは完全にその時その時であって、新入社員がやらないような業務もあるし、時勢にもよる。
俺が入社した時は、会社の意向でC、C++、C#という感じで研修を受けた。
C++はCのインクリメントで、Cの後継だ。
その次のC#は……Microsoftが出したものだから後継ってわけではないが……名前の由来はいくつかあるみたいだし……C言語というか、C言語の仲間の進化の歴史をなぞるように研修を受けたわけである。
予備知識
入社したてのペーペーのころ、プログラミングなんて一切触ったことがなかった……というのは嘘であった。
「めいたこと」はやっていた。
例えばHTMLとCSSでテンプレートを借りてきてホームページを作ったり、ツクールでゲーム作ったりである。
しかし、俺は目を輝かせてコンソールをたたくようなタイプではなく、何も身にはならず、別にたいした成果もなかったが、まあ苦痛じゃなかった。
それはそれで楽しかったよ。
経験と呼ぶにはアホくさいので主張することはなかったが、a=1
が代入を意味することくらいは知っていた。
四捨五入したら無くらいの経験である。
理由1 C#のほうが(実装が)ラクだから
まずこれだ、俺の性格上、一度味を占めると戻れなくなるので、低級言語から触っていったのはよかったと思う。
C言語
例えば、Cのころは文字列なんて高尚なものはなかった。
charの配列で扱うしかない。
char str[100];
strcpy(str, "Hello, World!");
文字列を操作するためにstrcpy関数を使用している。
配列のサイズを超えないように気を付けないとならないし、終端文字を正しく扱わないとならない。
C++
C++では、標準ライブラリにstd::stringクラスが導入され、これにより文字列操作が格段に簡単になった。
#include <string>
std::string str = "Hello, World!";
std::stringクラスはメモリ管理を自動化し、文字列の結合や比較、検索などの操作を簡単に行うことができる。
C#
さらに、C#では、stringクラスが標準的にサポートされているわけだ。
string str = "Hello, World!";
C#のstringクラスは、さらに強力だ。
ガベージコレクションによりメモリ管理も自動化された。これにより、プログラマーは文字列操作に関する低レベルの詳細を気にする必要がなくなり、より高レベルなロジックに集中することができるようになった。
理由2 Cのおかげで、ポインタという概念がわかった(なんとなく)
Cにはポインタという概念がある。
メモリの番地だけ格納しているよ、というようなものだ。
#include <stdio.h>
int main() {
int x = 10;
int *p = &x; // xのアドレスをポインタpに格納
printf("Value of x: %d\n", x); // xの値を表示
printf("Address of x: %p\n", (void*)&x); // xのアドレスを表示
printf("Value of p: %p\n", (void*)p); // ポインタpの値(xのアドレス)を表示
printf("Value pointed by p: %d\n", *p); // ポインタpが指す値(xの値)を表示
return 0;
}
ポインタのポインタとかポインタのポインタのポインタとかいわれると俺の頭の乏しいメモリがスタックオーバーフローするが、Cでポインタを習っていたため、C#で「参照型であり値が入ってない」という事象の意味がなんとなくわかった。
理由3 メモリリークを経験できた
メモリリークを経験したことがあるだろうか?
例えば、MFC (Microsoft Foundation Class) を使用している場合、GDI (Graphics Device Interface) オブジェクトのリソース管理は特に重要だ。以下に具体例を示す。
void DrawSomething(CDC* pDC)
{
CBrush brush(RGB(255, 0, 0)); // 赤いブラシを作成
pDC->SelectObject(&brush);
// 図形を描画
pDC->Rectangle(10, 10, 100, 100);
// ブラシを選択解除するのを忘れるとメモリリークが発生する
// pDC->SelectObject(&oldBrush); // 本来はこうするべき
}
このコードでは、ブラシオブジェクトを選択した後、元のオブジェクトに戻さないため、メモリリークが発生する。このようなリソースリークはアプリケーションが長時間実行されるときに深刻な問題を引き起こす。
CやC++でリソースを開放し忘れた時の被害たるや甚大である。
回収し損ねたリソースはじわじわとメモリを侵食し、年単位の時を経て、ある日突然パソコンごと、止まる……。
しかも原因が、どこにあるかわかりづらい。どっかが悪いんだろう。でもどこなんだろう? わからん。時限爆弾のような恐ろしい存在である。
C#からは、ガベージコレクションというのがいるのであんまり意識しなくていい。
メモリリークというのを経験しているおかげか、最後に後始末が必要なクラスかというのを比較的、ちゃんと見るようになったと思われる。
痛い目を見ておかないと身にならないことってあるよな。
感想
初学者にCから教えるのは結構アリじゃないかと思う。
ただ、あくまでも趣味人で、ハッキリやりたいことがあって、手っ取り早く動かしたいアプリがある場合はラクなツールを使ったほうがきっといいんじゃないかと思う。動いたら楽しいし。修行してる暇ってないだろうし。しかし学ぶ機会があるんならCから行ってみても楽しいんじゃないかな。
急にKotlinがいいらしいぞと聞いてKotlinを触ろうとしてみたり、それでやっぱり続かなくて飽きたり……。
俺は最初のほうのたくさんレベルアップしてできることが増える感じが痛快なので、たまに思い出したように新しめの言語に手を出しては飽きて自然消滅を繰り返している。
いずれにせよ、言語を変えてもいじってきた経験が無になるということはなく、相当に方向性が違わなければ、「まあ、やろうとしていることはなんとなく理解できる」という雰囲気はつかめるような気がする。
英語がわかると英語に似た文法の文章のいわんとすることがミリわかる感じだ。いや、わかんないけども。しかし、「まあ言語違っても、別に、簡単でしょ?(笑)」と言ってくる人間には「じゃあお願いします」と屏風から虎を出してもらいたくなるもんだけど。
唯一「これは思考回路が違うな?」と思うのが関数型プログラミングである。たぶん、関数型プログラミングをかじっていそうな人が書くC#は、ラムダ式が多く、俺にとってはかなり難解である(勉強になる)。
ほかには、JavaのフレームワークであるJava Spring Bootなんかも、かじってはみたが依存性注入などの部分がちょっと難しかったかな……。
あとはSQLなんかは、頭の使っている部分が違うなーと感じる。
終わりに
俺はC#のほうが総合的に好きだが、先輩はC++のほうが何もかも自分でできて安心できるため良いという。
たとえばシリアル通信なんかを実装するとき、C#だとクラスを使用して(公式のが非推奨になったのでサードパーティーのライブラリになったんだっけな)行うとラクなのだが、中でどうなってるのか気になるのだという。
そういう内部処理が問題で動かないとかライブラリが使えないとか、そういうことも確かにある。あと、人のライブラリを借りるとき、ライセンスは重要だ。
このあたり好みがありそうである。
俺より上の人間は、恐ろしいことにアセンブラから教わったという。
それはちょっと歯ごたえがありすぎるかな、と思う反面、地力は付きそうだなーと思う。
ポピポピ機械語を話せたら楽しそうである。
Cにも引き続きお世話になるし……といいつつも最近は組み込み系でもMicroPythonとか、最近の言語で書けたりするのであまり出番がない。
ほかの言語……たとえば、Pythonからプログラミングに入った人間というものがたくさんいると思うのだが、Cからはじめた俺からはどういう感じなのかといった想像があまりつかない。
たぶんどこから始めようともめったなことでは大差はなく、特に支障はないのではないかな、と思っている。
ほかの人のもちょっと見てみたいなあと思っているので、よかったら教えてね。