Emacs エディターで C 言語のプログラムを書く人向けに、入門用の解説がないように思う。そこで、知っておくと便利な機能をまとめてみた。

読者は、Emacs の操作とカスタマイズが最低限できる人を対象にしている。つまり、 C-x C-f といったショートカット・キーが使えて、 .emacs の設定ファイルがいじれる人。各機能について、基本的な使い方とその効果、あと最低限の設定について書き出した。

目次

1. ソースの色付け

Emacs は、C 言語のソース・ファイルを解析して、 if や for といったキーワードに対して、自動で色を付ける。

色を付けることでソースにメリハリが生まれ、可読性が上がる。また、スクリーン・ショットを見て分かる通り、コメントの閉じ忘れにも気付き易くなるメリットがある。

設定

Emacs 21 のユーザーは、以下のコードを .emacs に追加する。

;; 自動で色を付ける設定 (global-font-lock-mode t)

Emacs 22 以降では、デフォールトで色が付くので、設定の必要はない。

2. インデント

Emacs は C 言語のソースを解析して、構文に沿ったインデントを行なう。ユーザーは、ソース・コードを書く時に、インデントをどれだけ深くするか考える必要がない。インデントは、 TAB キーに割り当てられている。

例えば次のコードで、 TAB を打ってみる ( TAB は、インデントしたい行の上なら、どこで打っても構わない)。

void foo (void) { Foo(); if (CONDITION){ bar(); } Bar(); }

すると、下のように適切なインデントが為される。if 文の中は一つ深めのインデントになり、if の閉じ括弧も if と同じレベルにインデントされているのが分かる。また、インデントが深すぎた foo(); や bar(); が、ちゃんとインデントされていることも注目したい。

void foo (void) { Foo(); if (CONDITION){ bar(); } Bar(); }

インデントが C 言語の構文を解析してくれるおかげで、if 文の括弧の閉じ忘れなどに気がつき易くなるメリットがある。構文を理解しないインデントでは、こういうことは出来ない。

例えば、下のコードでは、二つ目の if 文の閉じ括弧を忘れてしまった。コードの書き手は、if 文を閉じたものと思い込んでいるので、else 文を一つ目の if 文と同じレベルに (手で) インデントしている。

void foo (void) if (CONDITION){ bar(); if (CONDITION II){ ... barbar(); } else {

Emacs のインデント機能を使っていれば、 else 文が一つ深くインデントされ、前の if 文が閉じられていないことに気づける。

関数全体のインデント

if 文の条件文を見直すなどして、ブロックのインデントが大きく変わることがある (ブロック全体のインデントが一つ下がるなど...)。そのような場合、各行に対してインデントを行なうのは面倒。代わりに関数全体をインデントするコマンドを使おう。

C-c C-q ( c-indent-defun ) 関数全体をインデントし直す

自動インデント用の設定

次のコードを .emacs に追加すると、自動改行+インデント機能が加わり、幸せになれる。

(add-hook 'c-mode-common-hook '(lambda () ;; センテンスの終了である ';' を入力したら、自動改行+インデント (c-toggle-auto-hungry-state 1) ;; RET キーで自動改行+インデント (define-key c-mode-base-map "\C-m" 'newline-and-indent) ))

3. アラインメント

Emacs には、連続する代入式などを整列 (alignment) させる機能がある。実行には、整列させたいコードをリージョンで囲み M-x align する。

例えば、次のソース・コードに対して M-x align すると...

/* Initialize options */ opt.encoding = AUTO; opt.output_format = PLAIN; opt.case_insensitive = false; opt.byte_insensitive = false; opt.count_escape = false; opt.merge = false; opt.overwrite = false; opt.print_0 = false; opt.print_sort = false; opt.sort_reverse = false; opt.verbose = false;

下記のように = 以降が同じ深さで揃えられ可読性が高まる。

/* Initialize options */ opt.encoding = AUTO; opt.output_format = PLAIN; opt.case_insensitive = false; opt.byte_insensitive = false; opt.count_escape = false; opt.merge = false; opt.overwrite = false; opt.print_0 = false; opt.print_sort = false; opt.sort_reverse = false; opt.verbose = false;

Emacs にはコメント・アウト用のコマンドが用意されている。通常使うのは、次の三つ。

M-; ( comment-dwim ) コメント・コード /* */ を埋め込み、文脈に合わせてインデントを行なう。 M-x comment-region リージョンをコメント・アウトする。 M-x uncomment-region リージョンのコメントを解除する。

C 言語のコメント書式は、コメントのネストに向いていない。例えば次のコード:

foo(); /* ホゲホゲする関数 */ bar(); /* フガフガする関数 */

これを、 foo(); の前の行に /* を、 bar(); の次の行に */ を置いてコメント・アウトしてみやう。すると、次のようにハイライトされる。

見て分かるように、関数 foo(); の後ろにある */ でコメントが終わってしまっている。このコメント・アウトのやり方では、関数 bar(); はコメント・アウトされない。

コメントをネストさせる場合は、次のようにする。

/* foo(); /\* ホゲホゲする関数 *\/ bar(); /\* フガフガする関数 *\/ */

Emacs のコメント・アウト機能は、こうしたコメントのネストにも対応している。たいした手間ではないからと、手でコメント・アウトなどせず、積極的にエディターのコメント機能を使うようにしませう。

5. info マニュアル

Emacs には、C の標準関数のリファレンス (英語) を参照する機能がある。 C-h C-i (Emacs 22 以降では C-h S ) で、 Describe symbols (default ***): と出てくるので関数名を入力、すると関数の説明を読むことができる。なお、 *** にはカーソル下にある関数名がデフォールト値として入る。

スクリーン・ショットは、関数 strtol のヘルプを表示させた所。

Emacs には、info と呼ばれるドキュメント・システムが搭載されており、各種マニュアルを読むことができる。ここで参照している info マニュアルは The GNU C Library Reference Manual (libc)。英語だけど、libc が提供している関数 (C の標準関数含む) を丁寧に解説している。

6. スペル・チェック

Emacs には ispell というスペル・チェッカーを呼び出す機能がある。よく使う ispell コマンドは以下の 3 つ。

M-$ ( ispell-word ) カーソル下のワードのスペル・チェックを行なう。 M-x ispell-region リージョンに対してスペル・チェックを行なう。 M-x ispell-comments-and-strings コメントと文字列だけを対象にスペル・チェックを行なう。

ispell-comments-and-strings はバッファー内のコメントと文字列だけを対象にスペル・チェックを行なう。プログラムをリリースする前に、一度は実行するようにしませう。

ispell の使い方

スクリーン・ショットは、 Charactor のタイポを ispell で修正している所。

別バッファーに修正候補が表示されるので、その中で正しい綴の番号 (or 記号) を入力する。スクリーン・ショットの場合、(0) 番目の Character が正しいので、 0 を入力。

ispell では、この他に次のコマンドが使える。

(スペース・キー) 一度だけ正しい単語として受け入れる i 正しい単語として辞書に登録する a 正しい単語として、このセッションの間受け入れる r 正しい単語をユーザーが入力する q ispell を終了する

flyspell-mode

Emacs には、自動的に ispell を実行する flyspell-mode と呼ばれるマイナー・モードがある。このモードをオンにしておくと、辞書にない単語を入力したらその単語がハイライトされて、スペルミスを知らせてくれる。単語の修正には、その単語の上で M-$ ( ispell-word ) を実行する。

C 言語の編集中は、flyspell の実行範囲を文字列・コメント内に限定する flyspell-prog-mode を使う。設定は以下の通り。

(add-hook 'c-mode-common-hook '(lambda () ;; flyspell-prog-mode をオンにする (flyspell-prog-mode) ))

関連ページ

新しい関数名や変数名を決める時に、ispell を使って英単語補完する方法もある。

Emacs には、タグ・ジャンプと言って、関数の定義へとジャンプする機能がある。関数が、別のファイルでで定義されていたら、Emacs はそのファイルを開いてその関数定義部分へとジャンプする。

タグ・ジャンプと呼ばれるのは、この機能を使うために予め TAGS というタグ・ファイルを作ることに寄る。

TAGS の作成

タグ・ファイルを作成するには、コマンド・ラインで次のようにする。

$ etags *.[ch]

(上級者向け) もし、サブ・ディレクトリーをいくつか作っているなら、トップ・ディレクトリーで次のようにする。

$ find . -name "*.[chCH]" -print | etags -

TAGS ファイルは、新しく関数を定義する度に作り直す必要がある。Makefile に次のように書いておくと、make し直す度に自動的に TAGS ファイルが更新されるので楽。

SRC = ソース・ファイル1.c ソース・ファイル2.c ... TAGS: $(SRC) etags *.[ch]

タグ・ジャンプは M-. に割り当てられている。

関数の上で M-. すると、 Find tag: (default カーソル下の関数名) と出るので、 RET を打つ。これで、関数の定義へとジャンプする。

なお、タグ・ジャンプを行なう時、最初に一回だけ Visit tags table: (delaut TAG) と出てくる。どのタグ・ファイルを読み込むのか聞いているのだけど、普通はそのまま RET を打てばいい。

タグ・ジャンプに関するコマンドで、よく使うのは以下の通り。

C-x 4 . 別ウィンドウを開いて、タグ・ジャンプする。 C-x 5 . 別フレームを開いて、タグ・ジャンプする。 M-* タグ・ジャンプする前の位置へ戻る。

8. 関数名の補完入力

Emacs は、TAGS ファイルを利用して、関数名を補完することができる。関数の最初何文字かを入力して M-TAB と入力する。すると、関数名の続きが補完入力される。もし、候補が複数ある場合は別バッファーに候補一覧が表示される。

補完入力を使うと、長い関数名をつけるも面倒でなくなるし、タイポもなくなる。

TAGS ファイルの作成方法については、前節「タグ・ジャンプの実行」を参照のこと。なお、関数の補完をする場合、最初に一度だけタグ・ファイルを読み込む必要がある。タグ・ジャンプを一度でも実行していれば、タグ・ファイルは読み込まれているけど、そうでない場合は次のコマンドを実行する。

M-x visit-tags-table

標準関数の補完入力

strtol や fscanf のような C 言語の標準関数を補完入力する場合は、 C-u M-TAB を使う。

※ C-u M-TAB は、libc のマニュアルから関数の補完を行なっている。従って、libc の提供する関数 (ex. ferror_unlocked ) の補完も可能。

9. コンパイルとエラー行ジャンプ

Emacs 使いは、Emacs から離れることなくコンパイルを行なう。

コンパイル

コンパイルをしたくなったら、 M-x compile と入力する。すると

Compile command: make -k

と出てくる。Makefile を書いていれば、そのまま RET を打つ。Makefile が何か分からない人は、 make -k を消して、 gcc ファイル名 と打つ。

スクリーン・ショットは、 M-x compile を実行した所。

画面が二つに分かれ、コンパイル・ログが表示される。見ての通りエラーがある。

エラー行ジャンプ

C-x ` と打つと、エラーのある行にジャンプする。エラーを修正したら、再び C-x ` を打つ。すると、次のエラー行へとジャンプする。これをエラーが無くなるまで繰り返す。

ソースの修正が終わったら、再び M-x compile しませう。

Emacs には、このエラー行ジャンプ機能があるので、 M-x goto-line (指定行ジャンプ・コマンド) の需要が小さい。

設定

コンパイルの度に M-x compile と入力するのは面倒臭い。ぼくは、次のコードを .emacs に入れて、 C-c c から compile コマンドを実行するようにしている。

;; C-c c で compile コマンドを呼び出す (define-key mode-specific-map "c" 'compile)

関連ページ

10. ChangeLog ファイル

Emacs には ChangeLog (変更履歴ファイル) を書くための機能も揃わっている。

変更を加えた関数にカーソルを持っていき、 C-x 4 a と打つ。すると、ChangeLog ファイルにその関数名が自動的に入力され、変更履歴を書ける。

スクリーン・ショットは、関数 fib に対する ChangeLog を書いているところ。

ChangeLog ファイルは、後でソースをどう編集したのかを知るのにとても便利。半年も経つと、過去の自分が別人のように思うことが多い。変更の目的・手段等をメモしておくようにしませう。

その他

この他、Emacs には、二つのバッファーを比較する ediff 機能、二つのファイルをマージする emerge 機能、RCS や CVS などのバージョン管理システムとの連携機能、デバッグ・ツール gdb との連携機能がある。ただし、これらの機能は、C プログラミングを始めたばかりの人達は使わなさそうなので、解説は割合する。

機会があれば、また後日、レビューを書きませう。

あとがき

C 言語を対象に、Emacs の便利な機能を解説した。しかし、ここで紹介したほとんどの機能は C 言語に限定したものじゃあない。ソースのハイライトからコメント・アウト、スペル・チェックにタグ・ジャンプ、コンパイルにエラー行ジャンプといった機能は、C++ でも Perl でも Ruby でも JavaScript でも使える。info さえ用意されていれば、マニュアルの参照も標準関数の補完入力もできる。

本エントリーを読んで、プログラミングに Emacs で何が出来るか、雰囲気だけでも掴んでもらえれば嬉しい。