CC-mode の簡単な使い方

C 系の言語 (C, C++, Java など) は、cc-mode が基本になっており、そこ から c-mode, c++-mode, java-mode などに派生しています。ですから、これ らの言語モードについては、設定方法がほぼ共通しています。

なお、筆者の現在使用している Emacs は GNU Emacs 21.3.1 です。

c-set-style

何はともあれ、c-mode のコーディング・スタイルを設定します。デフォル トでは GNU コーディング・スタイルになっていますが、はっきりいってこれ は亜流もいいところ。他のコーディング・スタイルにするには:

(defun my-c-mode-hook ()
  (c-set-style "linux"))
(add-hook 'c-mode-hook 'my-c-mode-hook)

といったように .emacs に書いておきます。選べるコーディング・スタイ ルには linux の他に bsd、k&r、そして gnu があります。

独自のスタイルを定義することもできますが、簡単ではないので省きます。 cc-mode の info を読んでください。

インデント

インデントしたいときは C-j で改行します。リターン・キーだとインデン トされません。行をインデントしたい場合、ポイントを行のどこかに置いてタ ブ・キーを押せば、タブ文字が挿入されずにインデントされます。タブ文字を 挿入したい場合には M-i とタイプします。

Emacs では、デフォルトのタブ幅は 8 スペースになっています。8 個のス ペースが並ぶようなところではタブになります。c-mode ではインデント幅は 8 スペースなので 1 タブに置き換えられます。java-mode ではインデント幅 は 4 スペースになります。タブ幅は変わず、8 スペースです。

たとえば、インデントを 4 スペースにし、かつタブ幅も 4 スペースにし たい場合:

(defun my-c-mode-hook ()
  (c-set-style "linux")
  (setq tab-width 4)
  (setq c-basic-offset tab-width))
(add-hook 'c-mode-hook 'my-c-mode-hook)

とします。

また、スペースだけでインデントしたい場合:

(defun my-c-mode-hook ()
  (c-set-style "linux")
  (setq indent-tabs-mode nil))

とします。

turn-on-font-lock

キーワードなどのハイライトも可能です:

(defun my-c-mode-hook ()
  (c-set-style "linux")
  (turn-on-font-lock))
(add-hook 'c-mode-hook 'my-c-mode-hook)

モードごとに設定するのが面倒ならば:

(global-font-lock-mode t)

と .emacs に書いておきます。

c-toggle-hungry-state

皆さんにぜひ使ってもらいたいのが hungry-deletion という cc-mode の マイナー・モードです。これは、連続する空白類をバックスペース・キー一発 でザッと消してしまうモードです。有効にするには:

(defun my-c-common-mode ()
  (c-toggle-hungry-state 1))
(add-hook 'c-mode-common-hook 'my-c-common-mode)

とします。c-mode-common-hook に追加することで、C 系のメジャー・モード すべてで有効になります。

1 文字ずつ消すには C-h をタイプします。ちなみに、C-h を delete-backward-char にに割り当てておくのは Emacs 使いの常識でしょう:

(global-set-key "\C-h" 'delete-backward-char)

キーボード・ナビゲーション

以下に紹介するキー操作は、はっきりいって知らなくても構いません。同 じ操作でもポイントの位置によって挙動が微妙に違ってきますし、キー操作を 身体で覚えるまで時間もかかります。

以下に紹介するキー操作は、M と C を同時に押します。PC ならば Alt と Ctrl を同時に押しつつ、たとえば a も押します。Esc を押してから C-a で も同じ効果が得られますが、ちょっとまどろっこしいのが難点です。

M-C-a beginning-of-defun 関数定義の先頭へ
M-C-e end-of-defun 関数定義の終わりへ
M-C-p backward-list 直前の開きカッコへ
M-C-n forward-list 直後の閉じカッコへ
M-C-b backward-sexp 直前のトークンへ
M-C-f forward-sexp 直後のトークンへ
M-C-u backward-up-list ネストから出る
M-C-d down-list ネストに入る

この中で便利なものは、M-C-a, M-C-e, M-C-u でしょうか。


compile

cc-mode のバッファでは M-x compile というコマンドが利用できます。実 際に試してみるとミニバッファに:

  Compile command: make -k

というプロンプトが現れます。そのバッファと対応するディレクトリに Makefile があれば、RET をタイプすることでビルドが始まります。もちろん:

  Compile command: make clean

のようなこともできますし:

  Compile command: gcc -g -Wall foo.c

のようなこともできます。

compile が実行されると、*compilation* というバッファが現れ、そこに 入力したコマンドの結果が表示されます。

ちょっと注目してほしいのが、ポイントが *compilation* に移っておらず、 元のバッファに置かれたままである点です。ここでコンパイル・エラーが起き たとしましょう。そのときは、ポイントを他のバッファに移さず、M-x next-error とタイプします。すると、コンパイル・エラーが起きた個所にポ イントが移動します。

つまり M-x compile でコンパイルし、エラーが起きたらそのまま M-x next-error をタイプするというサイクルになります。

M-x compile, M-x next-error と長々とタイプするのは面倒なので、筆者 は:

(defun my-c-common-mode ()
  (define-key c-mode-base-map "\C-cc" 'compile)
  (define-key c-mode-base-map "\C-ce" 'next-error)
  (c-toggle-hungry-state 1))
(add-hook 'c-mode-common-hook 'my-c-common-mode)

と .emacs に書いています。

また、*compilation* を消すために一々 C-x 1 をタイプするのは面倒なの で、C-x 5-2 で *compilation* だけの小さなフレームを用意しています。

デスクトップ

話が逸れますが、筆者のデスクトップを紹介しておきます。今のデスクトッ プは 4 つの仮想デスクトップを持ち、その 1 つの仮想デスクトップに 2 つ の Emacs と 1 つの端末エミュレータを立ち上げるという構成です:

+-----------+ +-----------+
|           | |           |
|           | |           |
|   src1.c  | |   src2.c  |
|           | |           |
|           | |           |
+-----------+ +-----------+
+-----------+ +-----------+
| *compi..* | |    rxvt   |
+-----------+ +-----------+

Emacs のフレームの大きさは 80x49 です。モニタには 17 インチの液晶を 使っていますが、2 つの Emacs を横に並べてスッポリと収まるようにしてい ます。これが最善かどうかは分かりませんが、参考まで


gdb

cc-mode とは直接関係はありませんが、ここで M-x gdb の簡単な使い方を 紹介しておきます。

M-x gdb というのは、その名のとおり、Emacs の中で gdb を動かすための コマンドです。つまり、Emacs が gdb のフロントエンドになるというわけで す。

M-x gdb とタイプすると:

  Run gdb (like this): gdb

とミニバッファにプロンプトが現れます。実行ファイルが a.out ならば:

  Run gdb (like this): gdb a.out

とタイプすると *gud-a.out* というバッファが開かれます。このデバッガ・ バッファでの操作は基本的に gdb と同じです。以降、よく使われるコマンド を簡単に紹介しますが、詳しくは gdb の info を参照してください。

core

もし core があるなら:

  Run gdb (like this): gdb a.out core

とタイプすることで core ファイルを指定できます。

core を指定したときに、まずやりたいことはスタック・トレースの表示で しょう。スタック・トレースを表示させるには:

  (gdb) bt

とタイプします。bt はもちろん backtrace のことです。

ブレイク・ポイント

gdb の中でプログラムを動かす前にブレイク・ポイントを設定します。

  (gdb) b main

ブレイク・ポイントには関数名の他に行数などでも指定することができま す。

run

ブレイク・ポイントを設定したら、いよいよプログラムを実行します:

  (gdb) run

もし、プログラムにコマンド行引数を渡す必要があれば、run で指定しま す:

  (gdb) run arg1 arg2

run で指定する引数は、一旦シェルによって解釈されます。ですから、必 要ならばエスケープしなければなりません:

  (gdb) run abc\ def \;

n

run を実行すると、ソース・バッファの左端に、これから実行される行を 示すカーソルが現れます。ブレイク・ポイントとして設定した関数の最初の行 になっているはずです。たとえば、次のような状態だとしましょう:

   int main(int argc, char *argv[])
   {
→    foo();
      bar();
      return 0;
   }

左の矢印 (→) を gdb のカーソルだと思ってください。このとき、n をタ イプすると、矢印が bar() の呼び出しに移ります:

   int main(int argc, char *argv[])
   {
      foo();
→    bar();
      return 0;
   }

この状態でもう一度 n をタイプすると return に移ります:

   int main(int argc, char *argv[])
   {
      foo();
      bar();
→    return 0;
   }

つまり、n は単純に今指されている行を実行し、次の行に移るというコマ ンドです。n は next のことです。

s

main から foo の中まで追いかけたい場合、s を使います。たとえば:

   int main(int argc, char *argv[])
   {
→    foo();
      bar();
      return 0;
   }

   void foo(void)
   {
     puts("hello, world");
   }

という状態のときに s をタイプすると:

   int main(int argc, char *argv[])
   {
      foo();
      bar();
      return 0;
   }

   void foo(void)
   {
→   puts("hello, world");
   }

というように gdb のカーソルが移動します。s は step のことです。

u と c

今の関数から抜けたい場合には u (up) を使います。

次のブレイク・ポイント (あるいは実行終了) まで一気に実行を行いたい ときには c (continue) を使います。

p

変数の中身を見るには p (print) を使います。p では式を指定することも できます:

  (gdb) p ptr->value

履歴

gdb は履歴を録っています。デバッガ・バッファでは M-p と M-n で履歴 をたどることができます。さらに、M-r で履歴を正規表現で検索できます。

また、RET だけをタイプすると、最後に入力したコマンドが繰り返されま す。


2005-07-26

tko@jitu.org