[Anthy-dev 2507] A coding style proposal for uim (was Re: コミットポリシーに関して)

Back to archive index

YamaKen yamak****@bp*****
2005年 10月 8日 (土) 10:56:57 JST


At Thu, 15 Sep 2005 07:40:43 +0900,
tkng****@xem***** wrote:
> コーディングスタイルなどに関しては触れていません。スタ
> イルもぼちぼちと統一していきたいところですが、これはまた後ほど。(私は
> コーディングスタイルには大して意見は無いので、誰かが発案してくれると嬉し
> いです。)

ついでに作ってみました。

NetBSDのstyleファイルから文言とスタイルを取捨選択したものに、今
まで我慢してた私の趣味を遠慮なしにムリムリと入れてあります。一般
的慣習から離れてる部分もあるんで、これを叩き台にして妥協点を探り
ましょう。

C++のスタイルを否定するコメントが多く入っていますが、決してジジ
イ根性から酸っぱい葡萄だと言ってるわけではありません。これでも
C++を第一の言語としていた時期もあるので。全て実際の経験に基づく
意見です。

それからコードは例示のために適当に書いたものなのでおかしなところ
もあります。ひどいところは直しますのでご指摘ください。

コメントお待ちしてます。
English comments are also welcome.


/* derived from: http://cvsweb.netbsd.org/bsdweb.cgi/src/share/misc/style?rev=HEAD&content-type=text/x-cvsweb-markup */

/*
 * Macros are capitalized.
 * If they are an inline expansion of a function, the function is defined
 * all in lowercase, the macro has the same name all in uppercase.
 * If the macro is an expression, wrap the expression in parenthesis.
 * If the macro is more than a single statement, use ``do { ... } while (0)'',
 * so that a trailing semicolon works.
 * Right-justify the backslashes to column 78; it makes it easier to
 * read. The CONSTCOND comment is to satisfy lint(1).
 */
#define MACRO(v, w, x, y)                                                    \
  do {                                                                       \
    v = (x) + (y);                                                           \
    w = (y) + 2;                                                             \
  } while (/* CONSTCOND */ 0)

#define DOUBLE(x) ((x) * 2)

/* Enum types are capitalized.  No comma on the last element. */
enum EnumType {
  ONE,
  TWO
} et;


/* Do inline return type and function name of a function prototype. */
int uim_init(void);

/* If the line overflows column 79, fold it at a comma. */
uim_candidate uim_get_candidate(uim_context uc, int index,
                                int accel_enumeration_hint);

/* If the line overflows column 79 even if folded, leave it untouched. */
void uim_set_prop_label_example(uim_context uc, int a_very_long_long_long_long_long_long_long_long_name);

/*
 * But if the parameter is a function pointer with direct type definition,
 * fold it into dedicated line.
 *
 * DO NOT declare a pointer in C++-style
 * E.g. use "void *ptr", not "void* ptr"
 */
void uim_set_prop_label_update_cb(uim_context uc,
                                  void (*update_cb)(void *ptr, const char *str));

/*
 * A function pointer with direct type definition must always be written
 * in single line even if its parameter can be folded.
 */
void uim_set_preedit_cb(uim_context uc,
                        void (*clear_cb)(void *ptr),
                        void (*pushback_cb)(void *ptr, int attr, const char *str),
                        void (*update_cb)(void *ptr));

/*
 * DO NOT declare a pointer in the C++-style such as "char* p".
 *
 * Even if the "char*" style notation does not cause compile error, such
 * coding style is a bad habit that leads a human error from
 * misinterpretation on a type declaration.
 * 
 * For example, a declaration "char* a, b, c;" may sometimes be
 * interpreted as "char* a; char* b; char* c;" by less-experienced C/C++
 * programmers. But it of course results "char* a; char b; char c;". The
 * notation imitating 'ideal' type definition such as "'cp' is a 'char*'"
 * is a poisonous syntax sugar. To keep original semantic interpretation
 * over a type of C, do not use it. "char *cp" should be readable as
 * "applying '*' operator to the 'cp' makes char".
 * 
 * So we should write pointers as "char *" style. "char *a, b, c;" will
 * not cause such misinterpretation. We should remind that the uim library
 * will be used by wide-range of programmers. We should make efforts for
 * eliminating sources of human errors.
 */
static const void *vp;            /* Not "void* vp;" */
static const char *cp, **cps, c;  /* Not "char* cp," */

/*
 * The function type must be declared on a line by itself
 * preceding the function.
 */
static const char *
select(int argc, char *argv[])
{
  /*
   * Separate variable declaration block and subsequent codes by a blank
   * line, and DO NOT initialize variables in the declarations. This makes
   * an abstract about what this function does, in combination with the
   * function name, at a glance.
   *
   * DO NOT declare a pointer in C++-style such as "char* p".
   * DO NOT declare a variable in a middle of block as C++/C99-style.
   */
  int score, best_score;
  int (*evaluate)(const char *);
  const char *cp, *selected, *candidate, **candidates;

  // DO NOT USE C++/C99-STYLE COMMENT!

  /* No spaces after function names. */
  if ((result = function(a1, a2, a3, a4)) == NULL)
    exit(1);

  /* Unary operators don't require spaces, BINARY OPERATORS DO. */
  a = ((b->c[0] + ~d == (e || f)) || (g && h)) ? i : (j >> 1);
  k = !(l & FLAGS);

  /*
   * DO SPACE AFTER KEYWORDS (while, for, return, switch).  No braces are
   * used for control statements with zero or only a single statement,
   * unless it's a long statement.
   *
   * Forever loops are done with for's, not while's.
   */
  for (p = buf; *p != '\0'; ++p)
    continue;  /* Explicit no-op */
  for (;;)
    stmt;

  /*
   * Use `!' for tests even if it's not a boolean.
   * E.g. use "if (!*p)", not "if (*p == '\0')".
   *      use "if (!p)",  not "if (p == NULL)".
   *
   * Developers should aware of type of the variable without such explicit
   * type-specific comparison.
   *
   * The heart of the C language is that all primitive types define zero
   * as the false value, and it can directly be a boolean conition. Making
   * it obsolete is an excessive anti-incorrectness movement of C++-ism, I
   * think.
   */
  best_score = 0;
  for (candidate = *candidates; candidate; candidates++) {
    score = 0;
    for (cp = candidate; *cp; cp++) {
      if (*cp == ' ')
        score = -1;
    }
    /*
     * An inequality expression should always be written as
     * (lesser < greater) order regardless of which side is the
     * subject. It helps visualizing the numeric positions as a number
     * line in an intuitive interpretation, especially in a range
     * comparison as follows.
     *
     * Ruby: (worst..best) === n
     * C:    (worst <= n && n <= best)
     */
    if (0 <= score)
      score = (*evaluate)(candidate);
    if (best_score <= score)
      selected = candidate;
  }

  /*
   * Casts and sizeof's are not followed by a space.
   *
   * Use `!' for tests even if it's not a boolean.
   * E.g. use "if (!*p)", not "if (*p == '\0')".
   *      use "if (!p)",  not "if (p == NULL)".
   *
   * DO NOT cast a pointer in C++-style.
   * E.g. use "(int *)p", not "(int*)p"
   *
   * Do not use C++ style '0' for a NULL pointer.
   * Routines returning ``void *'' should not have their return
   * values cast to more specific pointer types.
   *
   * Use uim_err/uim_warn (may be added), don't roll your own!
   */
  if (!(four = malloc(sizeof(struct foo))))
    uim_err(1, NULL);
  if (!(six = (int *)overflow()))
    uim_err(1, "Number overflowed.");
  while (*strp++)
    continue;

  /*
   * Closing and opening braces go on the same line as the else.
   * Don't add braces that aren't necessary except in cases where
   * there are ambiguity or readability issues. But if a body
   * statement of if-else sequence has braces, all other parts must
   * also have even if single statement.
   */
  if (test) {
    /*
     * I have a long comment here.
     */
#ifdef zorro
    z = 1;
#else
    b = 3;
#endif
  } else if (bar) {
    stmt;
    stmt;
  } else {  /* Add braces even if single statement */
    stmt;
  }
  /* single statement does not need braces */
  if (test)
    stmt;
  else if (bar)
    stmt;
  else
    stmt;


  /*
   * Elements in a switch statement that cascade should have a FALLTHROUGH
   * comment.  Code that cannot be reached should have a NOTREACHED comment.
   */
  while ((ch = getopt(argc, argv, "abn")) != -1) {
    switch (ch) {           /* Indent the switch. */
    case 'a':               /* Don't indent the case. */
      aflag = 1;
      /* FALLTHROUGH */
    case 'b':
      bflag = 1;
      break;
    case 'n':
      errno = 0;
      num = strtol(optarg, &ep, 10);
      break;
    case '?':
    default:
      usage();
      /* NOTREACHED */
    }
  }

  /*
   * Parts of a for loop may be left empty.  Don't put declarations
   * inside blocks unless the routine is unusually complicated.
   */
  for (; cnt < 15; cnt++) {
    stmt1;
    stmt2;
  }

  /* Second level indents are also two spaces. */
  while (cnt < 20)
    z = a + really + long + statement + that + needs + two lines +
      gets + indented + four + spaces + on + the + second +
      and + subsequent + lines;

  /*
   * a return statement at end of a function should be separated by a
   * blank line.
   * No parentheses are needed around the return value.
   */
  return selected;
}

-------------------------------
ヤマケン yamak****@bp*****



Anthy-dev メーリングリストの案内
Back to archive index