2013年11月24日日曜日

日経Linux2013年12月号

昔、BASICマガジンからプログラムの勉強をはじめました。今はコンピュータ系やプログラミングの雑誌も減って寂しいものです。そんな中、今私が定期的に購入しているのは「日経Linux」です。Linuxの勉強のためですが、それほど中身を読む時間がないのが残念です。

今月の記事の紹介とその感想です。

特集1
 Ubuntuデスクトップでスタート!
 サーバー超マスター100ステップ

私はFedoraをデスクトップで使っていますが、困ったことにあまりサーバーとしては使っていないです。なかなかサーバーとして使う用途が思いつかないので、その当たりでいい説明があると良いのですが・・・

特集2
 激安ボードで即楽しめる!
 知識ゼロから始めるLinuxモノ作り

Raspberry Pi、BeagleBone Black, Arduino, mbed,を使った電子工作の記事です。初心者向けで、LEDと温度センサーを使ったものです。RPiでLEDはやってみたのですが、すぐに飽きました(笑)。やはり使い道が必要ですね。

特集3
 要注目のモバイルLinux!
 最新Chrome OSで 軽量マシン

実際にはChrome OSでなく、オープンソース版のChrominum OSをビルドからインストールまでを行う記事です。WindowsXPの期限が切れた後のノートPCに入れると良さそうな感じがします。

特別連載
 Windows ユーザーのためのLinux超入門
 第3回 主要アプリケーションとパッケージ管理

WindowsXPの期限切れが迫る中、Linuxは選択肢の1つですが、移行は難しいですね。Linuxを初めて使ったとき、Windowsよりも便利な点があって驚いたのですがまずはインストールが難関です。

まつもとゆきひろの言語の世界
第7回 JavaScript

Rubyを開発したまつもとゆきひろさんの記事で楽しみな記事の1つです。色々なプログラミング言語の思想などがまとめられています。

#!シス管系女子Season2
第2話 鍵認証で安全にログインしよう

みんとちゃんのボケがいつも楽しみです(笑)
 

マンガでこういう風に分かりやすく説明できるのは羨ましいです。


C/C++ 演算

コンピュータで一番得意なのは足し算や掛け算などの演算でしょう。

value = 3 * 4 + (-4) / (1 + 1);

まずはデータとして値を代入する必要がありますが、それを示すのがイコール(=)です。C/C++では以下の点が注意です。
  1. 数学的なイコールと意味が違い、代入を意味する。
  2. イコールの左側を左辺値といい、変数の必要があり、変数の値を書き換える。
  3. イコール自身も式となっており、代入値を返す。
最後の3の意味が分かりにくいかもしれませんが、以下のように右辺に書くこともでき、足し算などと同様に扱うことができると言うことです。ある意味2がイコール特有の処理と言えるかもしれません。

value2 = (value = 3 * 4 - (-4) / (1 + 1));


残りの文はアスタリスク(*)が掛け算、スラッシュ(/)が割り算を示す演算を表すということ意外は数学的な記述とほとんど同じで意味が解ると思います。演算には優先順があり括弧内から計算して行きます。また加減算より乗除算の方を先に計算します。最初の記述では、4という結果がvalueに代入されます。演算を表す文字を演算子と言い、通常の計算に使う演算子は算術演算子と言い、他にも余り(剰余)の計算でパーセント(%)があります。

C/C++として特徴的な演算子として 代入と計算を一緒に出来る演算子があることです。これは別の書き方ができますが、よく使うことからソースコードを簡単に書くことができるようにしたものです。

同等の式備考
value++;value = value + 1;全体の評価が終わった後に+1する。
++value;value = value + 1;全体の評価を行う前に+1する。
value--;value = value - 1;全体の評価が終わった後に-1する。
--value;value = value - 1;全体の評価を行う前に-1する。
value += 10;value = value + 10;+=の他にも-=,*=,/=,%=,&=,|=,^=が使用できる。

++value; と++value;の違いは分かりにくいですが、a = ++value; a = value++;と他の演算と記述すると違いが分かります。前者では、aにvalue+1が代入され、後者ではaにvalueが代入されます。



C/C++らしい演算子としては、他に2進数での計算を行うビット演算子があります。00110を1のシフトの場合に01100と左にシフトする左シフト(<<)、00011と右にシフトする右シフト(>>)があります。またビットごと論理和、論理積、排他的論理和、論理否定をおこなう演算があります。論理和など聞きなれない言葉かもしれませんが、意外とよく使うため、覚えておいた方が良いです。

aba | b (論理和)a & b (論理積)a ^ b (排他的論理)~a (論理否定)
000001
011011
101010
111100



また用途は計算と全く違うのですが、C/C++では演算子となっているもので、比較演算子があります。下記は「もしaが3と等しかったらaを1引く」と言うプログラムですが、このa == 3 のような条件を指定する部分も比較を行う演算子となっています。

if (a == 3) a--;

比較演算子には小なり(<)、小なりイコール(<=)大なり(>)、大なりイコール(>=)、非等価(!=)、等価(==)があります。これらの演算の結果はC++の場合にはbool型と言う型となり、trueまたはfalseのどちらかの演算結果となります。C言語の場合には、int型で比較結果が真(正しい)のとき1を偽(間違っている)のとき0の演算結果となります。

 代入(=)も演算子であり、以下の文も記述としては間違いではないのでコンパイル時にエラーとなりません。等価(==)と間違えないように注意が必要です。(gccの場合、コンパイル時に-Wallというオプションを付けることで条件のところで代入(=)が使用されていた場合にで警告を出すことは可能です)

if (a = 3) a--;



また、このような真偽の専用の演算子として、論理演算子の論理否定(!)、論理和(||)、 論理積(&&)があります。ビット演算子と違いビットごとの演算はせず、値が0であれば0と、値が0以外であれば1として計算をします。

また論理和(||)、 論理積(&&)は唯一演算を端折る場合がある演算子なので注意が必要です。例えば以下の式の場合、a == 1の比較演算を行い、偽だった場合には、b == 2 と c = 2の処理は行いません。左から演算していくときにその後の演算がどうであっても、結果が偽となるためです。しかし、b == 2 については問題ないとしてもその後、c = 2 の代入が行われないことは、その後cの値を使用するときに前の比較演算の影響が出ることになります。

(a == 1) && ((b == 2) && (c = 2))


他にもprintf()という関数の呼出をこれまで使っていましたが、この記述も関数呼出の演算子とみなされます。そのため、 以下のような記述も可能です。

 a = a + printf("Hello");

上述のようにC/C++の記述は演算子の固まりで出来ています。これらの演算子は全て繋げて書くことができますが、全ての演算子には足し算と掛け算では掛け算を先に行うように優先順位と言うものが存在します。例えば以下の場合にはaにどのような値が入るでしょうか?

 a = 3 << 1 + 1;

答えは12になります。左シフト(<<)より加算(+)の方が優先順位が高いため 3 << (1 + 1)と同等になるためです。

さらに優先順位が同じ場合には、結合規則が存在し、左から右に計算していくものと、右から左に計算していくものがあります。例えば加算(+)は左から右で a + b + c + d の記述は ((a + b) + c) + d と同等です。代入(=)は右から左で a = b = c = d は a = (b = (c = d))と同等になります。

 詳しくはWikipediaなど他の資料を参考してください。 他にも様々な演算子があったり、演算子は意外と奥が深いですが、C言語は演算子の記述の固まりであることと、優先順位に困った時には括弧を付けて優先順位をコントロールすることなど、注意点を覚えておけば、まずは良いかと思います。

2013年11月17日日曜日

Fedora 20 Beta (GNOME 3.10)

Fedora 20 の Beta版が出ました。でもあまり変わっているところは無い気がします。カーネルのバージョンも3.11でした。12/10に正式版が出る予定です。

Fedora 20 になって一番変わる所と言えばGNOME3.10かもしれません。そこで、簡単にレビューです。GNOME 3.10の紹介の詳細についてはここです。

まず、UbuntuでiBus1.5について問題になっていたので日本語入力についてです。Fedoraでは比較的問題は無いのですがやはり分かりにくいです。日本語キーボードを使うには入力ソースに「日本語」というものと「日本語(かな漢字)」の2つを入れる必要があります。一旦「日本語」に変えると「日本語(かな漢字)」もキーボードのレイアウトが切り替わるという不思議な仕様となっています。これはFedora 19と変わらずです。




見た目が大きく変わったのは、メニューとヘッダーバーです。よりグラフィカルに、より表示エリアを大きくということでしょうか。もともとツールバー部分もタイトルバーと同様に掴んで移動などができました。これはタッチインターフェースでは掴みやすく便利と思っていたのですが、狭くなってしまいました。表示エリアが大きくなって良かったのだろうか・・・。


新しいソフトウェアとして、「ソフトウェア」や「地図」があります。「ソフトウェア」は今までのGUIのパッケージインストーラに比べると使いやすそうですが、やはりコマンドラインのyumの方が便利な気がします。「地図」はGoogle Mapに比べれば全然使えないのでしょうが、日本でも市の検索ぐらいは使えそうです。ちなみにこの「地図」はJavascriptで作られているようです。


それと細かい所ですが、Gnome3.10ではスクロールバーを2秒ほど掴んでいると、スクロールバーの線が細くなり、より細かくスクロールできるようになっています。しかし、GTK+3のライブラリを使っているところだけのようで、GTK+2を使っていると思われるFirefoxなどでは使えなさそうでした。

C/C++ 数値と名前と変数

動画や画像に音楽などコンピュータは色々なことができますが、
コンピュータの基本は電気が流れる流れないの0と1の世界です。

0と1だけで表した数値を2進数と言います。通常私達がつかっているのは10進数で、

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

の十個目で二桁になります。2進数の場合は

 1
10

と2個目で二桁になります。これらを10進数に割り当てれば数値が扱えることになります。 括弧内は2進数を10進数に変換するための計算式です。2の4乗とは 2×2×2×2→8です。

  1 → 1   (                            2の0乗 × 1)
 10 → 2   (              2の1乗 × 1 + 2の0乗 × 0)
 11 → 3   (              2の1乗 × 1 + 2の0乗 × 1)
100 → 4   (2の2乗 × 1 + 2の1乗 × 0 + 2の0乗 × 0)
   :
   :
10100 → 20 (2の4乗 × 1 + 2の3乗 × 0 + 2の2乗 × 1 + 2の1乗 × 0 + 2の0乗 × 0)

2進数の場合は、桁数が多くなりすぎますが、 10進数と2進数では桁上げのタイミングが違いすぎるので、 8進数や16進数が使われます。特に16進数がよく使われます。


10進数2進数8進数16進数
0000
1111
21022
31133
410044
510155
611066
711177
81000108
91001119
10101012A
11101113B
12110014C
13110115D
14111016E
15111117F
16100002010
17100012111
::::


そして2進数の1つの1と0のデータの単位をビット(bit)、16進数で2桁(2進数で8桁)の0〜FF(0〜255)の単位をバイト(byte)と呼びます。

プログラムで計算などを行うには、メモリを使いますが、コンピュータとしてはメモリも100番地と150番地のデータのように数値で区別して扱います。通常の場合は1つの番地に1バイトのデータを記憶できます。

しかし、こんな数値ばかりでメモリを管理していたら大変です。ソースコードでは大抵、メモリを管理するためには自分で名前を付けた「変数」を使用します。

階乗の計算のソースコードでは、value, fact, iが変数です。自由に名前を付けれますが、英字の大文字小文字、数字、アンダーバー(_)が使用できます。先頭に数字は使用できません。せっかく自由なので分かりやすい名前にしましょう。iは分かりにくく感じると思いますが、繰り返し処理に使用される因子(iterator)の意味から来ているもので、よく使われる定石みたいな物となっています。

この変数の前についているintは「型」といって、データの意味を表すものとなっています。main()内の先頭行ではvalue, fact, iがint型であることを宣言しています。

最近のPCでは、intは32bit(4バイト)で10進数だと−2,147,483,648 から 2,147,483,647の値のデータと言う意味です。計算結果がこの範囲を越えることをオーバーフローといい、計算結果が意図通りにならない原因の1つです。

小数点を扱いや、マイナスの扱いも2進数で扱います。どのように扱うかは、IEEE754や、2の補数を調べてみてください。

2013年11月10日日曜日

C/C++ 階乗の計算

コンピュータと言えば計算が得意です。ですから計算のプログラムを作ってみます。計算は階乗(factorial)の計算で、nという数字を与えた時に、1×2×3×4×・・・・×(n-1)×nという1からnまでを掛けた値になる計算です。なお0の階乗は1となります。

まずはどのように動くかという仕様を決めます。これだけのプログラムでも色々と考える必要があります。
  1. コマンドライン引数で階乗の数値を入力する。
  2. コマンドライン引数で入力した数値から階乗を計算する。
  3. 計算した結果をコンソールに表示する。
  4. 引数では数値を入力する。数値以外は0と見なす。
  5. 数値がマイナスの場合はエラーを表示し、2を返す。
  6. 小数点がついていた場合は、小数点以下を無視する。
  7. 引数の数が1つでない場合はエラーを表示し、1を返す。
  8. 値のオーバーフローは考慮しない。
上記のように動くソースコードを書きます。fact.cとします。


コンパイルし、実行を行うと以下のようになります。



ソースコードの解説を簡単にします。

ソース説明
main(int argc,  char *argv[])今回はmain()関数にint argc, char *argv[]という2つの引数がついています。argcは整数(int)で、引数の数を表します。argvは引数の文字列の配列を意味します。*や[]の意味はまた機会があれば説明します。とりあえずargv[1]などが一つ目の引数の文字列と解釈してください。
int value, fact, i;valueと、factと、iという名前の整数のデータ領域を作成しています。
if (argc != 2) {...}引数の数(argc)のチェックを行っています。引数の数にはコマンド自身の数も含まれるので引数が1つのときには2となります。!=2はargcが2で無いかどうかという計算で、その結果により、{...}内の処理を行います。

value = atoi(argv[1]);
引数の文字列argv[1]を整数値に変換して、valueに代入しています。文字列のままでは計算ができないためです。atoi()というのは文字列を整数値に変換するライブラリ関数です。stdlib.hに入っているのでstdlib.hを#includeしています。
if (value < 0) {...}引数を整数値に変換したvalueが0より小さい場合に{...}の処理をします。
fact = 1;factというデータ領域に1を代入します。
for (i = 1; i <= value; i++) {...}繰り返し処理を行い、階乗を求めています。(1)iのデータ領域に1を代入します。(2)iがvalue以下の値か調べ、iがvalue以下の値であれば、{...}の処理を実行し、そうでなければ{...}の次の行の処理に移ります。(3){...}内の処理が終わったらi++を実行します。i++はiの値をi = i+1と同じ意味でiの値に1つ値を足します。
fact = fact * i;アスタリスク(*)は掛け算の意味です。iが1つずつ加算するのを繰り返すことで、階乗を計算します。
printf("factorial = %d¥n", fact);
階乗の値を出力します。printf()で表示する文字列の指定内のパーセント(%)には意味があり、%dは整数(int)の表示を行うことを意味します。文字列の後ろの引数に%dに表示するデータを列挙します。

複雑になりましたが、それは今回のプログラムがユーザーからのコマンドラインからの入力が増えたことが原因です。これでもオーバーフローを考慮しないなど、処理が少なくなるようにサボっています(17の階乗でなるはずの無いマイナス値となっているのはオーバーフローのためです)。

通常の場合、プログラムはユーザーの入力に対し、何かの処理を行います。ユーザーの入力は何があるか分からないので、入力を制限する処理を入れたり、どのような入力でもチェックによりエラーを返すなどの処理を入れなくてはいけません。そうしないと 想定外の問題が起こることになります。

この想定外の問題をいかにして少なくすることができるかが、プログラマの腕の見せ所の1つです。

それと、今回はCPUの処理(演算と制御)の部分とメモリ(データ領域の作成)の部分がHello Worldに比べて多く増えています。それらについてはまた次回。

2013年11月4日月曜日

MinGW + MSYS で日本語

C/C++ Hello Worldでは、わざと日本語の使用を避けていました。日本語を扱うには色々と問題があり、設定などが難しかったためです。

gccのコンパイルで警告になることがある

printf("Hello World¥n");でなく、 printf("こんにちは¥n”);とした場合は問題になりませんが、printf("ソフトウェア¥n”);とした場合にはコンパイル時に警告が表示されます。

なぜかというと円マーク(¥)が原因です。円マークは文字コードが0x5Cなのですが(Linuxでは0x5Cの表示がバックスラッシュ(\)の場合もあります)、Windowsが標準で使用している文字コードのCP932(ShiftJISの一種)では、「ソ」は0x83,0x5Cの2バイトとなっていて、コンパイラが2つ目の0x5Cを円マーク(¥)と間違うためです。他にも「表」などが同様に問題があります。


その対策では、--input-chaset=CP932というオプションを付けます。するとgccは文字コードをUTF-8 に変換してからコンパイルします。しかし、これだけではprintf()で文字化けします。--exec-charset=CP932とすることで、実行ファイル内部の文字列をCP932に変換します。



そもそもvimで日本語入力ができない

まずはvimで日本語が化けます。この対策で、.vimrcの最後の行に
set enc=japan
と入れると良いようです。ここを参照させていただきました。

しかし、日本語入力はうまく行きません。Alt+半角/全角で日本語入力への切換ができるのですが、vimの画面では変な風にスクロールしていってしまいます。
この対策にはminttyを使うと良いようです。以下でセットアップできます。

$ mingw-get install msys-mintty

"mintty -"(ハイフンが必要)を実行するか、msys.batを起動するときに -minttyオプションを付けるとminttyがが起動します。mintty上で起動したvimであれば日本語入力が出来ます。ここを参照させていただきました。以下はminttyの画面です。



さらに日本語ファイル名を使う

上記ではlsで日本語のファイル名がまた文字化けしますし、入力もできません。以下を行うと日本語ファイル名が使えるようになります。

/etc/profileのファイルを編集して最後に以下を追加します。
alias ls='ls --show-control-char'

また、~/.inputrcを編集して16行目以降を以下のように変更します。
# disable/enable 8bit input
set meta-flag on
set input-meta on
set output-meta on
set convert-meta off

同じくここを参照させていただきました。

MinGW + MSYS で GTK+3

GTK+のバージョン3はなかなかWindows版が出なかったのがやっと出たようです。インストール方法も載っていますが、MSYSで使うのであれば、より簡単かもしれません。

all-in-on bundleをダウンロードして、C:¥MinGW¥msys¥1.0に解凍して上書きします。

その後、MSYS上で以下のコマンドを実行します。
$ pango-querymodules > \etc\pango\pango.modules
$ gdk-pixbuf-query-loaders > \lib\gdk-pixbuf-2.0\2.10.0\loaders.cache
$ gtk-query-immodules-3.0 > \lib\gtk-3.0\3.0.0\immodules.cache

たぶん、これでいいはず・・・
コンパイル方法も全く一緒で、これと同じプログラムが動きます(-mwindowsオプションは付けたほうが良いかもしれませんが)。