公開技術情報

[English] [Japanese]

lctags で C 言語の関数コールを簡単に

ある関数をコールする際、その関数の名前がうろ覚えの場合や、 使いたい関数がどのヘッダで定義しているか分からないケースが多いと思います。

lctags では、そのような場合でも簡単に関数補完できる方法を提供しています。

使用方法

関数コールしたい箇所で M-x lctags-insert-call-func します。

あるいは、C-c l i c を入力します。

mini buffer に funcname-pattern: の入力が求められるので、 使用したい関数名の一部を入力します。

入力した関数名にマッチする関数の一覧がリストされるので、 そのリストから関数を選択します。

もしも、その関数を定義するインクルードファイルをインクルードしていなかった場合、 インクルードすべきファイルがリストされます。

なお、使用したい関数を定義しているヘッダーファイルを、 事前に lctags に登録しておく必要があります。

hello world サンプル

https://www.youtube.com/watch?v=gMgyNMBmqws

上記リンクは、実際に emacs で操作した際の解説動画です。

simple.c で hello world 出力するサンプルです。

DB 生成

まずはプロジェクトディレクトリのトップで DB を生成します。

$ lctags init .

ソース登録

プロジェクトのソースを登録します。 ここでは simple.c を登録します。

$ lctags addStdInc
$ lctags build gcc test/simple.c

addStdInc は、C の標準ヘッダを登録します。

simple.c は次の内容です。

int main() {
  const char * hello = "hello ";

}

関数コール

simple.c を emacs で開いて 3 行目の空行に移動し、次を入力します。

C-c l i c

次に mini buffer に、使用した関数名の一部を入力します。

ここでは write を入力します。

すると、 関数名に write を含む関数一覧がリストされます。 このリストは、DB に登録してあるファイル内で定義された関数情報を元に生成します。

リストの中から、 fwrite を選択します。

すると、次にヘッダファイルの選択になります。 このサンプルでは、何も include していないため、 fwrite を使用するにはヘッダファイルを include する必要があります。

リストされているヘッダファイルには、 先頭に fwrite を直接宣言しているヘッダ stdio.h がリストされ、 残りは stdio.h を include しているヘッダがリストされます。

ヘッダを選択すると、 fwrite() の関数プロトタイプと、必要なヘッダが展開されます。

int main() {
  const char * hello = "hello ";
  fwrite( const void * __restrict __ptr, size_t __size, size_t __n, FILE * __restrict __s ) => size_t
    // #include </usr/include/stdio.h>
}

次に、fwrite の第 1 引数に hello を指定し、 fwrite の第2引数には strlen( hello ) を指定します。

strlen をコールするとき、再度関数展開 C-c l i c を利用します。

mini buffer には、 len と入力します。

これにより len を含む関数一覧がリストされるので、strlen を選択します。

strlen を利用するために必要な string.h がまだ include されていないため、 ヘッダ選択モードになります。

ヘッダを選択すると、次のようになります。

int main() {
  const char * hello = "hello ";
  fwrite( hello, strlen( const char * __s ) => unsigned long, size_t __n, FILE * __restrict __s ) => size_t
    // #include </usr/include/string.h>
    // #include </usr/include/stdio.h>
}

fwrite の残りの引数を適宜指定し、 展開された #include をファイル先頭に移動し、コメントを外します。

#include <string.h>
#include <stdio.h>
int main() {
  const char * hello = "hello ";
  fwrite( hello, strlen( hello ), 1, stdout );
}

次に world を出力するため 再度関数展開 C-c l i c を利用します。

ここでは put を指定します。 リストに表示されている関数から puts を選択すると、次のように展開されます。

#include <string.h>
#include <stdio.h>
int main() {
  const char * hello = "hello ";
  fwrite( hello, strlen( hello ), 1, stdout );
  puts( const char * __s ) => int
}

ここで include が展開されません。 なぜなら puts は stdio.h に定義されており、 stdio.h は既に include 済みだからです。

最後に puts() の引数を次のように編集して終了です。

#include <string.h>
#include <stdio.h>
int main() {
  const char * hello = "hello ";
  fwrite( hello, strlen( hello ), 1, stdout );
  puts( "world" );
}