main関数の書き方

投稿日: / 更新日:

本職はプログラマなつもりですが、半年以上コード書いてません(´・ω・`)

それはさておき、関数名称とかは命名規約などを作るときにいの一番に決めつけられるところだと思うのですけど、C/C++言語に限定するとmain関数だけは必ず例外設定されることになります。

それが何となく気持ち悪いというか…

それを良い事に——おそらく、名前を初めとした全体の構成を考えるのを面倒くさがって——膨大な行数のmain関数を書く人が居たりして、結構害悪なのではないかと思うことも多々ある訳です(^_^;)

で、なんとなく自分が書いてる形を晒してみようかと。

 

命名規約

そもそも、命名規約などはプロジェクト単位などで決められる事が多いです。

なので、そうしたノウハウはプロジェクト全体として共有されていて、当該プロジェクトに参加している人であれば、ある程度は名前から中身が類推出来る様になっているはず…

 

ところが、それがmainのままだとわかりづらいですよね…ということで。

 

例えばhogeというコマンドを作るとき、基本的には「メイン」の処理はhogeという関数名にします。ここに命名規約に沿ったプリフィクスだとかサフィクスだとか大文字だとか小文字だとか、そういう装飾をするだけ。

# Pythonとかだとそもそもそのままですがw

で、名前を変えることが出来ないmain関数は、そのhoge関数を呼び出すだけの存在で、非常にすっきりした物にします。

個人的にはこれだけで全体的な構成がわかりやすくなる気がしています。

 

構成

命名規約の話から構成の話にすっとびましたが、僕は命名規約はモジュール構成を表す為の形式の一つだと思っているので、余り離れた部分の話ではないつもりです。

# どういったモジュール(含クラス)構成にしているのか、わかりやすくなっているのが良い命名規約です

 

main関数は命名規約も特殊ですが、引数の与えられ方も特殊です。

なので、その辺りのパラメータを処理する部分は余り汎用的ではない、main関数独特の形になりやすいため、そこはそのまま処理してしまいます。

メイン関数の構成

↑ 落書きそのままぽいですが、基本的にこんな感じの組み方をしています( ´ ▽ ` )ノ

 

その後、パラメータに応じて、実際の処理部分を実行するようになります。

左側のパターンは、素直にそのまま処理をすすめるパターン。
右側のパターンは、引数毎に(任意個数のファイル名を受け取るなど)順次処理を行うようなパターン。

後は、それぞれ実際の処理としてやるべきことを粛々とこなしているというのが見やすいのではないかなと( ´ ▽ ` )ノ

 

イメージとしてはこんな感じです。

#include <stdio.h>
#include <unistd.h>

/**
 * EX: echo [-n] [string ...]
 */

void
echo (bool aShowNL, int aParamCount, char *aStringArray[])
{
  for (int i=0; i < aParamCount; ++i) {
    if (i != 0) putchar (' ');
    printf ("%s", aStringArray[i]);
  }
  if (aShowNL) putchar ('\n');
  return ;
}

int
main (int argc, char *argv[])
{
  bool shownl = true;
  int c;
  do {
    c = ::getopt (argc, argv, "n");
    switch (c) {
    case 'n':
      shownl = false;
      break;
    default :
      c = -1;
      break;
    }
  } while (c != -1);

  echo (shownl, (argc - optind), (argv + optind));
  return 0;
}

# echoという題材がよろしくなかったことは深く反省しております…


- スポンサードリンク -