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;
4. コメント
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 を使って英単語補完する方法もある。
7. タグ・ジャンプ
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 で何が出来るか、雰囲気だけでも掴んでもらえれば嬉しい。
Emacs は 6, 7 年くらい前までよく使っていましたが、アラインメントや C の標準関数のリファレンスが参照できる機能は知りませんでした。
ReplyDelete今はもうほとんどプログラムは書かないのですが(書いても使っているのは vi(vim) だったりして)、改めて Emacs の奥深さに感心しますね。
そう言って頂けると、この記事を書いた甲斐もあるってものです。ありがとうございます。
ReplyDelete私は Emacs が好きでしょうがないのですが、それでもまだ知らない事が山積みです :) こんな感じに Emacs に興味を持つ人を増やせたら嬉しいです。
Xkeymacsを使ってWindowsのほとんどの操作をEmacsライクに使っていますが、EmacsでCのソースを書くことは無かったので参考になりました。
ReplyDelete私もEmacs大好きなのでこの特集はありがたかったです。
エラー行ジャンプは「C-`」ではなく「C-x `」ではないでしょうか。
ReplyDeleteうわー。穴があったら入りたい。
ReplyDeleteおっしゃる通りです。修正しました。
素朴な疑問なんですが、コンパイルした後、できたファイルを実行するにはどうするんでしょう?
ReplyDeleteなにか便利な仕組みが用意されているのでしょうか?
Emacs には、M-x shell や M-x eshell とすることで、サブ・シェルを起動する機能があります。この機能を使えば、Emacs から離れることなしに、できたファイルを実行することができます。
ReplyDelete過去記事では、ここら辺が参考になるかと。
- clmemo@aka: Emacs の subshell で ls に色を付けない
- clmemo@aka: Emacs で複数 subshell を起動する
- clmemo@aka: .emacs_SHELL という shell の設定ファイル
- 徒然な覚書 : ls on M-x shell
ありがとうございます。
ReplyDeleteシェルを使うとなると、vi でサスペンドして実行ファイル起動、fg するのと大して変わりませんね。
それすら面倒に感じる場合に、最速かつ汎用的な方法はないものかと考えているのですが。
> シェルを使うとなると、vi でサスペンドして...
ReplyDeleteparasporospa は、「それすら面倒に感じる」領域に入ってしまわれているのですね ^^; その領域の人を唸らせる回答をするのは難しいですが :p
# 一行コマンドを実行する M-! (shell-command) はもちろんご存じですよね。
Makefile に実行コマンドまで書いておくというのはどうでしょう。
下のような Makefile を書いておき
foo: foo.o
$(CC) $(CFLAGS) $^ -o $@
exec-foo: foo
./foo&
Emacs で「M-x compile RET make exec-foo」とすれば、コンパイル後、続けてファイルの実行までやってくれます。対話的に実行するのに比べると自由度が低くなりますが、絞切り型の処理ならば快適度は高くなるかと。
自分は秀丸エディタを使用しています
ReplyDeleteインデントで自動で改行とか
結構便利です
お金はフリーソフト製作者
ということで一応免除
してもらえますし・・・
色分けもできます
でもEmacsの色分けきれいですね
自分は色分けで設定しつくすの
結構めんどくさくて・・・
秀丸で色指定の無いものを
自分でどんどんカスタマイズして
つかってるといったところでしょうか・・・
annkokunokizinn さん、こんにちは。
ReplyDelete秀丸もよいソフトウェアですよね。私も (Emacs が難しくて使えないという) 友人には秀丸をすすめています :)
たいへん参考になりました
ReplyDeleteありがとうございます
コメントありがとうございます。
ReplyDelete記事が参考になって、こちらも嬉しいです。
私はC言語を書くときにEmacsを使っていますが、全く機能を使っておらず、宝の持ち腐れでした。
ReplyDeleteとても参考になりました。ありがとうございます。
Kozonoyuki さん、はじめまして。Emacs は機能がありすぎて、目が回りそうですよね。この記事が一助になったと聞き、うれしく思います。
ReplyDelete