2013年10月22日火曜日

[c] (広義の)コンパイルの工程

分かっていなかった事が分かったので
コンパイルの工程を復習するために hello.cに依存しているtest.cのコンパイル過程を
FreeBSD 9.1 RELEASE で出力してみた。

-hello.h-
#ifndef HELLO_H
#define HELLO_H

int sayHello(void);

#endif

-hello.c-
#include "stdio.h"
#include "hello.h"

int
sayHello(void)
{
  printf("hello\n");
  return 0;
}

-test.c-
#include <stdio.h>
#include "hello.h"

int
main(int argc, char **argv)
{
  sayHello();
  return 0;
}


なお、あらかじめhello.cは中間ファイル(オブジェクトコード)hello.oを生成済み。

$ gcc -o test -save-temps -v hello.o test.c

-save-temps … 通常は、削除される中間ファイルをカレントディレクトリに残す
-v … 途中コマンドを標準エラー出力にコマンドのバージョン情報も含めて出力する

以下が出力したコマンド

Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070831 patched [FreeBSD]
 /usr/libexec/cc1 -E -quiet -v -D_LONGLONG test.c -fpch-preprocess -o test.i #1
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/gcc/4.2
 /usr/include
End of search list.
 /usr/libexec/cc1 -fpreprocessed test.i -quiet -dumpbase test.c -auxbase test -version -o test.s #2
GNU C version 4.2.1 20070831 patched [FreeBSD] (amd64-undermydesk-freebsd)
compiled by GNU C version 4.2.1 20070831 patched [FreeBSD].
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: a8daf30220ba0c32c21af96787b683e6
 /usr/bin/as -V -Qy -o test.o test.s #3
GNU assembler version 2.17.50 [FreeBSD] 2007-07-03 (x86_64-unknown-freebsd) using BFD version 2.17.50 [FreeBSD] 2007-07-03
 /usr/bin/ld --eh-frame-hdr -V -dynamic-linker /libexec/ld-elf.so.1 -o test /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib -L/usr/lib hello.o test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o #4
GNU ld 2.17.50 [FreeBSD] 2007-07-03
  Supported emulations:
   elf_x86_64_fbsd
   elf_i386_fbsd


#1 プリプロセス
cc1 がコンパイラ本体らしい
以下が出力されたtest.i の一部
マクロ展開とインクルードファイルの中身の出力が行われていることが確認できる。

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 39 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 40 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/sys/_null.h" 1 3 4
# 41 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/sys/_types.h" 1 3 4
# 33 "/usr/include/sys/_types.h" 3 4
# 1 "/usr/include/machine/_types.h" 1 3 4
# 51 "/usr/include/machine/_types.h" 3 4
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short __int16_t;
typedef unsigned short __uint16_t;
typedef int __int32_t;

=中略=

# 2 "test.c" 2
# 1 "hello.h" 1



int sayHello(void);
# 3 "test.c" 2

int
main(int argc, char **argv)
{
  sayHello();
  return 0;
}

#2 アセンブリコード生成


-test.s-
.file "test.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB3:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
subq $16, %rsp
.LCFI2:
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call sayHello
movl $0, %eax
leave
ret
.LFE3:
.size main, .-main
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zR"
.uleb128 0x1
.sleb128 -8
.byte 0x10
.uleb128 0x1
.byte 0x3
.byte 0xc
.uleb128 0x7
.uleb128 0x8
=以下略=


#3 アセンブル
アセンブルのコードを機械語に変換 オブジェクトファイル(*.o)を出力する


#4 リンク
必要なライブラリをリンクして、最終的な実行形式ファイル(ELF)を出力する。
以下は、出力されたバイナリに依存する共有ライブラリを表示

$ ldd test

test:
libc.so.7 => /lib/libc.so.7 (0x800819000)


2013年10月20日日曜日

[FreeBSD] style(9) 単語

man style(9) の翻訳で分からなかった単語の意味を列挙します。

implicit 暗に示す
assume 思い込む
silent on 言及しないで
History is silent on this event. 歴史は、この事件に関しては何も記していない。
brevity 簡潔な
trim 削減する
onlike in this one これとは違って
obtain B from A AからBを得る
elsewhre そのほかの場所では、
(a) applicable 適用可能である
enclose 囲む
okay to A Aして大丈夫です。
side effect 副作用
either どちらか一方
parentheses 確固
expantion 拡張
right-justigy 右寄せにする
encapsulate 要約する
compound statement 複合ステートメント
invocation 呼び出し
conditionally 条件的に
discern がわかる。はっきりと認める。
subjectively 主観的に
corresponding 一致する、対応する
preceding 先行する、前述の、上記の、先立つ
abbreviate 略して書く
identifier 識別子
in preference to A Aに勇戦して。 Aよりはむしろ。
overiding 他の全てに優先する
qualifier 修飾語句
suffice 満足させる
know if A is B AがBであるかどうかを知る
whereas であるのに ところが に反して
convention 慣習 しきたり、
elsewhere ほかの場所
relevant a 関連のある
preferably なるべく むしろ 好んで
compelling 強制的な むりやりの
precedent 慣例
either A or B AまたはB A,Bのどちらでも A,Bのいづれかを
preferable より好ましい
line up 整列する
briefly 簡単に
consistency 一貫性
obvioud 明白な
complicate 複雑にする
unary 単項の
binary operator 二項演算子
precedence 先行、上位
obvious 明白な
desire 強く願う
elicit 誘い出す、引き出す
complaint 不平、ぐち
whatever〜 どんな〜でも
compliant with に従う
consistent with 調和して、矛盾しないで
apporoximately ほぼ
diverge 分岐する、離れる
desire 要望
practice 実践



[FreeBSD] style(9) 難訳箇所について

man style(9) の翻訳で訳すのが難しいと感じた箇所について日本語翻訳マニュアルの訳を見てみます。

1) Be careful to check the examples before assuming that style is silent on an issue.

-> styleがこれらの例について言及していないと決めつける前に、注意して例を確認してください。

assume: 決め付ける

2) All VCS (version control system) revision identification in files obtained form else where should be maintained.

->  全てのVCS(バージョン官吏システム)リビジョン識別子は、存在すれば維持します。

obtain: 手に入れる
maintain: 維持する、持続する


3) In declarations, do not put any whitespace between asterisks and adjacent tokens, except for tokens that are indentifiers related to types.

-> 宣言の中では、型に関係づけられたトークンを除いて、アスタリスクと隣接したトークンの間には空白文字を置きません。

4) for example you need to know if the typedef is the structure itself or a pointer to the structure.

-> 例えば、typedefが構造体そのものであるか、構造体へのポインタであるのか、あなたか知る必要があります

A need to know if B.: Aは、Bであるかを知る必要がある。

5) In general code can be considered "new code" when it makes up about 50% or more of the file(s) involved.

-> ファイルの50%以上かそれ以上を巻き込んだ修正の場合は一般にコードは、”新しいコード"とみなすことができます。

involve: 巻き込む

6) ANSI C says that such declarations have file scope regardless of the nesting of the declaration.

-> ANSI Cによるとこの様な宣言は、宣言のネスティングによらず、ファイルスコープになります。

regardless of A: Aにもかかららず


7) Code that is approximately FreeBSD KNF style compliant in the repository must not diverse from compliance.

-> リポジトリの中のおおよそFreeBSD KNF style に適合しているコードは、この適合から離れてはなりません。

compliant: 準拠している
diverse: 別種の、異なった


2013年10月15日火曜日

[FreeBSD] styleの自力和訳

英語の鍛錬のためにstyle(9)を自力で英訳してみた。

FreeBSD カーネル開発者用マニュアル

#NAME#
   style -- カーネルソースファイル書式ガイド

#DESCRIPTION#

このファイルでは、FreeBSDソース群の中でもカーネルソースファイルの推奨される
書式を規定している。またこれは、ユーザー向けのプログラムのコードの書式
ガイドでもある。多くの書式規則が例文とともに示されている。その書式が
重要な点について記していないと思う前によく例をチェックされい。

/*
* FreeBSDの書式ガイド。CSRGのカーネル標準書式(KNF)に基づいた。
*     @(#)style     1.14 (Barkeley) 4/28/95
* $FreeBSD release/9.1.0/share/man.style.9 217807 2011-01-07 08:34:12Z trasz $
*/

/*
* "とても"重要な1行のコメントは、この様に書く。
*/

/*
* 複数行のコメントは、この様に書く。普通の文章と同じように。普通の文章の
* 段落分けと同じように記述する。
*/

著作権の表示は、複数行であるべきだ。一行目は、アスタリスクの後にダッシュを続け
次の様に書く。

/*-
* Copyright (c) 1982-2025 John Q. Public
* All rights reserved.
*
* 長く退屈なライセンスは、ここに書く。しかし、完結かつ短く。
*/

スクリプトは、ソースツリーから"/*-"から始まるコメントの全てをライセンス情報として収集する。
もし、indent(1)の1文字目から始まるライセンスや著作権表示ではないコメントを再整形しないフラグ
を立てることを望む場合は、そのコメントのダッシュをアスタリスクに変更せよ。1行目以外の
コメントは、ライセンス文として考慮されない。

著作権ヘッダーの後に、空行を入れる。そして、C/C++以外のソースファイルのための$FreeBSD$。
バージョンコントロールIDタグ一つのファイルに1つのみ含まれるべきである(これとは違い)。
C/C++以外のソースファイルは、上記の例の様にあるべきである。C/C++のソースファイルにおいては、
以下の1つに準拠する。ファイルの全てのVCS(Version control system) の版は、
その他のファイルでは、メンテナンスされ、含まれ、適用可能で、複数のIDがファイルの履歴を
示す。総じて、外部のIDとインフラを編集すべきではない。ラップされることなしに("#if
defined(#LIBC_SOCS)")、非互換のビットを隠し、IDをオブジェクト
ファイルに含ませないために"#if 0... #nedif"で囲む。ファイル名が変更された
場合、外部のVCSIDの直前にのみ"From: "を追加する。

#if 0
#ifndef lint
static char sccsid[] = "@(#)style 1.14 (Barkeley) 4/28/95":
#endif /* not lint */

#endif

#include <sys/cdefs.h>

__FBSID("#FreeBSD: release/9.1.0/share/man/man9/style.9 217087 2011-01-07 08:34:12Z trasz $"):

ヘッダーファイルの前のその他の空行は、そのままにしておく。

通常は、カーネルのインクルードファイル(例: sys/*.h)が最初に来る。
<sys/types.hと<sys/param.h>の両方ではなく、どちらか一方をインクルードする。
<sys/types.h>は<sys/coefs.h>インクルードする。そして、<sys/types.h>は、
<sys/coefs.h>に依存して問題ない。

#include <sys/types.h> /* ローカルではないインクルードは、<>で囲む */

ネットワークプログラムにおいては、次にネットワーク関係のインクルードファイルを次に書く。

#include <net/if.h>
#include <net/if_dl.H>
#include <net/route.h>
#include <netinet/in.h>
#include <[protocolos/wrhod.h>

カーネルのソースに/usr/includeにあるファイルを使ってはいけない。

次のグループの前に空行を置く。/usr/includeにあるファイルは、アルファベット順で
ソートされていなければいけない。

#include <stdio.h>

グローバルなパスは、<paths.h>で定義されている。プログラム固有のローカルパスは、
ローカルの"pathnames.h"に記述する。

#include <paths.h>

ユーザー固有のインクルードファイルの前に空行を置く。

#include "pathnames.h" /* ローカルのインクルードファイルは、ダブルクオートでくくる*/

実装名前空間でアプリケーションインターフェースを実装する場合を除いて#define したり名前
を宣言してはいけない。

"unsafe"マクロの名前(副作用を伴う)と内容が明白なマクロの名前は、全て大文字にする。
語句のようなマクロの拡張は、一つのトークンか括弧の外を持つ。#defineと
マクロ名の間には、タブ一つを置く。もしマクロがインライン関数の拡張ならば、関数名は、全て小文字
にする。読みやすくするためにバックスラッシュを右寄せにする。もし、マクロが複合ステートメント
ならば、それをdoループで囲む。そうすればif文の中で安全に使うことができる。文章の終端の
セミコロンは、華奢なプリンターやエディタのパースを簡単にするべくマクロよりむしろ
マクロの呼び出しによっておかれるべきだ。

#define MACRO(x, y) do { \
variable = (x) + (y); \
(y) += 2; \
} while(0)

コードが#ifdefや#ifを使い条件的にコンパイルされる時、マッチする#endifや
#elseに続き、読み手が容易に条件付きコンパイルのコード部分の終わりが
分かるようにコメントを追加するかもしれない。そのコメントは、
(主観的に)当該コード部分が長いと思われる場合、20行を越える場合、#ifdef
のネストが読み手を混乱させる可能性がある場合にのみ用いられるべきである。
例外は、lint(1)の目的のために条件付きコンパイルされない複数のケースのために作られるかもしれ
ない。これは、コンパイルされるコードが少ない場合においてさえそうである。コメントは、
1つのスペースで#endifや#elseと離すべきである。短い条件付きコンパイル部分に対しては、
近接したコメントは、つけるべきではない。

#endifへのコメントは、対応する#if、#fidefと表現を一致させるべきである。#else,#elif
へのコメントは、先行する#if、#elif文と逆の表現とすべきである。コメントにおける、
"defined(FOO)"のような準表現は、"FOO"と略される。コメントの目的は、"#ifndef FOO"は、
"#if !defined(FOO)"として扱われる。

#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef COMPAT_43
/*A large region here, or other condional code. */
#else /* !COMPAT_43 */
/* Or here. */
#endif /* COMPAT_43 */

#ifndef COMPAT_43
/* Yet another large region here, or other conditional code. */
#else /* COMPAT_43 */
/* Or here */
#endif /* !COMPAT_43 */

プロジェクトは、古いBSDスタイルのu_intxx_t式の整数識別子よりむしろISOIEC 9899:1999
("ISO C99") uintxx_t式の符号無し整数の識別子を使うべくゆっくり動いている。新しい
コードは、後者を使うべきである。そして、もし、他の主要な作業が終わり格別の理由がなければ
そのエリアにある古い様式を、新しい様式に変換すべきである。何もないコミットの様に、ケアは、uintxx_tのみのコミットにすべきである。

列挙型の値は、全て大文字である。

enum enumtype {ONE, TWO} et;

識別子における内側の_アンダースコアの使用は、cammelCaseやTitleCaseにもまして
好まれる。

宣言部においては、トークンが型に関連した識別子である場合を除いて隣接したトークンと
アスタリスクの間にスペースを開けてはいけない。(それら識別子は、基底型の名前、修飾子、
独立して宣言されるものと言うよりむしろtypedefで定義されるものである。)
それら識別子は、スペース一つでアスタリスクと分けなさい。

構造体のメンバを宣言する時、使用する順番、サイズ(大きいものから小さいもの)
、アルファベット順でソートして宣言しなさい。最初のカテゴリは、通常適用されない。
しかし、例外がある。1つのメンバーは、1行で宣言しなさい。可読性を向上させるため
メンバー名をあなたの裁量で1つまたは2つのタブで整列するよう努めなさい。一つのタブは、
少なくともメンバーの90%が揃う場合にのみ使用するべきである。とても長い型に続く
名前は、スペース1つで分離すべきである。

主要な構造体は、構造体が使われるファイルの先頭で宣言するすべきである。
また、構造体が複数のソースで使われる場合は、ヘッダーファイルに分離すべきである。
構造体の使用部と宣言部は、分離すべきであり、ヘッダーファイルで宣言されている
場合は、externすべきである。

struct foo {
struct foo *next; /* List of active foo */
struct mumblue amumble; /* mumble のコメント    */
int bar; /* コメントを揃えるように */
strcut verylongtypename *baz /* 2つのタブで揃わない場合 */
};
struct foo *foohead; /* グローバルなfooリストの先頭 */

可能な時は常に、自分でリストを回すのではなくてquese(3)マクロを用いよ。
従って、前述の例は、次の様に書くのが好ましい。

#include <sys/queue.h>

struct foo {
LIST_ENTRY(foo) link; /* fooリストには、queueマクロを用いる */
struct mumble amumble; /* mumbleのコメント */
int bar; /* コメントを揃えるように。 */
struct verylongtypename *baz; /* 2つのタブで揃わない場合 */
};
LIST_HEAD(, foo) foohead; /* グローバルなfooリストの先頭 */

構造体の型にtypedefsを用いるのは、避けなさい。Typedefsは、元の型を適切に
隠さないので、問題を抱えがちである。例えば、typedefが構造体自身もしくは構造体への
ポインターかどうかを知る必要がある。加えてそれらは、正確に1回宣言しなければいけない。
ところが、不完全な構造体の型は、不必要であるにもかかわらず何回も記述することができる。
Typedefsは、独立したヘッダーファイルで用いいるのが難しい。typedefを定義するヘッダーは、
用いられるヘッダーより以前に、用いられるヘッダによって(名前空間の汚染をもたらす)インクルード
されなければいけない。また、それらは、typedefを含むことに対するバックドアでなければいけない。

慣習がtypedefを必要とするとき、その名前は、構造体のタグ名と一致させるべきである。Standard C
もしくはPOSIXで指定されている場合を除いてtypedefの最後を"_t"とするのは避けなさい。

/* 構造体の名前は、タグ名と一緒にせよ */
typedefi struct bar {
int level;
} BAR;
typedef int foo; /* これは、foo */
typedef const long baz; /* これは、baz */

全ての関数は、どこかでプロトタイプ宣言されている。

(ほかの場所から使われない)プライベートな関数のプロトタイプ宣言は、ソースコードの
一番最初に持っていくべきである。ソースコード内のみで使われる関数は、staticと
宣言すべきである。

カーネルの別の部分から使われる関数は、関連のあるインクルードファイルでプロトタイプ宣言される。
関数のプロトタイプ宣言は、論理的順序で列挙するべきである。他の順番を使う
明白な理由がない場合は、なるべく、アルファベット順を使うべきである。

一つ以上のモジュールから使用されるローカルな関数は、"extern.h"のような別のヘッダーファイルに
含めるべきである。

__Pマクロを用いるべからず。

総じて、50%以上ファイルが影響を受けるコードは、"新しいコード"と認識される。これは、
既存のコードの慣例を崩すのに十分である。現在のstyleガイドラインに従いなさい。

カーネルは、パラメータの型にに関連付けられた名前を持つ。以下カーネルでの使用例。

void function(int fd);

ヘッダーファイルにおいては、ユーザーランドのアプリケーションに対して見えるようにせよ。
見えるプロトタイプ宣言は、(アンダーバーから始まる)"protected"な名前か名前のない型のどちらか
を用いなければいけない。purotectedな名前を使う方が好まれる。

void function(int);



void function(int _fd);

プロトタイプ宣言は、関数の名前を揃えるためにタブの後に多くのスペースを含むかもしれない。

static char *function(int _argc, const char *_arg2, struct foo *_arg3,
                     struct bar *_arg4);
static void *usage(void);

/*
* 全ての主要なルーチンには、何をするかということを簡単に説明したコメントをつけるべきである。
* mainルーチンの前のコメントは、このプログラムが何をするかを説明すべきである。
*/
int
main(int argc, char *argv[])
{
char *ep;
long num;
int ch;

一貫性のために、オプションをパースするときは、getopt(3)を用いるべきである。
オプションは、switch文の一連の流れの一部ではなく、getopt(3)の呼び出しとswitch文の中で
ソートされるできである。switch文の中の要素であるcascadeには、FALLTHROUGHコメントを
つけるべきである。数の引数に対しては、精度をチェックすべきである。明白な理由に到達不可能な
コードは、/* NOTREACHED */とマークされるかもしれない。

while((ch = getopt(arc, argv, "abNn:")) != -1)
switch (ch) { /* switch文をインデントせよ */
case 'a': /* case文はインデントしない */
aflag = 1; /* case文本体は、1つのタブでインデント */
/* FALLTHROUGH */
case 'b':
bflag = 1;
break;
case 'N':
Nflag = 1l
break;
case 'n':
num = strtol(optarg, &ep, 10);
if (num<= 0 || *ep != '\0') {
warnx("illegal number, -n argument -- %s",
      optarg);
usage();
}
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;

 (if, while, for, return, switch)の後には、スペースをいれよ。ステートメントが
一行以上になる許される場合の除いてゼロもしくは1ステートメントと共にブレース("{""}")を
ステートメントを制御するために用いてはいけない。無限ループは、whileではなく、forを用いよ。

for (p = buf; *p != '\0'; ++p)
/* nothing */
for (; :)
stmt;
for (; :) {
z = a + really + long + statement + that + needs +
   two + lines + gets + indented + for + spaces +
   on + the + second + and + subsequent + lines;
}
for (; ;) {
if (cond)
stmt;
}
if (val != NULL)
val = realloc(val, newsize);

 forループの一部は、空になるかもしれない。ルーチンが特殊で複雑な場合を除いてブロック内で
宣言をしてはいけない。

for (; cnt < 15l cnt++) {
stmt1;
stmt2;
}

 インデントは、8文字のタブにすること。2段目のインデントは、4つのスペースにすること。もし、
長いステートメントとなる場合は、演算子を行の最後に書くこと。

while (cnt < 20 && this_variable_name_is_too_long &&
   ep != NULL)
z = a + really + long + statement + that + needs +
   two + lines + gets + indented + four + spaces +
   on + the + second + and + subsequent + lines;
 行末に空白を入れては、いけない。タブは、空白の後ろにインデントを揃えるためにのみ使いなさい。
タブよりも多くのスペースを使ってはいけない。タブの前にスペースを入れてはいけない。

 ブロックの始まりと終わりのブレースは、elseと同じ行に書きなさい。不必要なブレースは、
いれない。

if (test)
stmt;
else if (bar) {
stmt;
} else
stmt;

  関数名の後にスペースを入れない。コンマの後には、スペースを入れよ。'('や'["の後に
スペースを入れない。')'や']'の前にスペースを入れない。

error  = function(a1, a2);
if (error != 0)
exit(error);

 単項演算子にスペースは、必要ない。二項演算子には、スペースが必要である。優先させる必要がある
場合や複雑なステートメントの場合を除いて()を使ってはいけない。他人は、自分より
混乱しやすいかもしれないということを覚えておこう。下記のコードが理解できるか?

a = b->c[0] + ~b == (e || f) || g && h ? i : j >>1;
k = !(l & FLAGS);

 処理に成功した場合は、0を返し、失敗した場合は、1を返せ。

exit(0); /*
 * "処理成功時は、0を返す"の様な
 * 明白なコメントは、避けよ。
 */
}

関数の返り値の型は、"function"の前の行に書きなさい。関数の中身を書くための右ブレースは、
1行に書きなさい。

satic char *
function(int a1, int a2, float fl, int a4)
{

 関数内で変数を宣言する時、サイズ順->アルファベット順で宣言しなさい。複数の変数を
1行でまとめて宣言するのは、OK。もし、一つの型の変数が1行に収まらない時は、複数行に
分けて、型名を行頭に書きなさい。宣言部で変数を初期化することによってコードが
分かりにくくなることのない様に気を付けなさい。このことについては、あまりシビアに
ならなくても良い。初期化部において関数の呼び出しをしてはいけない。

struct foo one, *two;
double three;
int *four, five;
char *six, seven, eight, nine, ten, elven, twelve;

for = myfunction();

 関数の中で関数を宣言しては、いけない。ANSI Cにおいては、そのような
不注意な入れ子の宣言は、ファイルスコープを持つ。ローカルスコープに現れる
ファイルスコープは、思わぬ不平を良いコンパイラから引き出す。

キャストとsizeofの後にスペースを入れては、いけない。ちなみに、indent(1)は、
このルールに依らない。sizeofは、丸括弧とともにかかれる。sizeof(var)インスタンスに
冗長な丸括弧のルールを適用しては、いけない。

 NULLは、空のポインタ定数を好む。アサイメント等コンパイラが型を知っているコンテキストにおい
ては、(type *)0や(type *)NULLの代わりにNULLを使え。その他のコンテキスト、特に全ての関数の
引数においては、(type *)NULLを使え。(もし、関数のプロトタイプ宣言がスコープにない場合、キャ
ストは、可変長引数においては必要であるが、その他の引数に対しては、不必要である。)
ポインタのNULLチェックの例

(p=f()) == NULL

悪い例:

!(p = f())

論理型でないにもかかわらず、チェックに!を使うな。次の様にすべきである。

IF (*p == '\0')

悪い例:

if (!*p)

 void *を返すルーチンは、返り値を勝手にキャストして返してはいけない。
 return文における値は、丸括弧で囲むべきである。

 err(3)やwarn(3)を使え。自分で実装するな。

if ((four = malloc(sizeof(struct foo))) === NULL)
err(1, (char *)NULL);
if ((six = (int *)overflow()) == NULL)
errx(1, "number overflowwed")'
return (eight);
}

 この様な古い様式の関数宣言。

static char *
function(a1, a2, f1, a4)
int a1, a2; /* 整数型の宣言。これらをデフォルトにしてはいけない。*/
float f1; /* floatとdoubleのプロトタイプの違いに注意せよ。 */
int a4; /* 順番が宣言されたリスト */
{

 明白にK&Rとの互換性が必要な場合を除いて、ANSIの関数宣言を使いなさい。長いパラメータの
リストは、4つの普通のスペースでインデントしなさい。

 可変長の引数は、次の様にすべきである。

#include <stdarg.h>

void
vaf(const char *fmt, ...)
{
vs_list ap;

va_start(ap, fmt);
STUFF;
vs_end(ap);
/* void型を返す関数においては、return文は不要である */
}


static void
usage()
{
/* 関数に、ローカル変数がない場合は、空行を入れる。 */

 どんなにそれが、早くきれいだとしても、おろかなバグに気を使わなくても良いように
fputs(3),puts(3),putchar(3)ではなくて、printf(3)を使いなさい。

 Usage文は、マニュアルページのSYNOPSISのようにあるべきである。そして、
下記順番になっているべきである。

1.  オペラントの必要ないオプションを一番最初仁1組のラケット"[]"の内側にアルファベット順
で書く。
2.  オペランドが必要なオプションを次に、同じくアルファベット順でブラケットの内側に書く。
3.  必要な引数があれば、次にコマンドラインで指定すべき順序で書く。
4.  最後に、残りの任意の引数をブラケットの内側に同じくコマンドラインで指定すべき
順序で列挙する。

 バーは、"どちらか一方の"オプション、引数を分離する。共に指定すべき複数のオプション、引数は、
一組のブラケットの内側に書く。

"usage: f [-aDde] [-b b_arg] -m m_arg] req1 req2 [opt1 [opt2]]\n"
"usage: f [-a | -b] [-c [-dEe] [-n number]]\n"

(void)fprintf(stderr, "usage" f [ab]\n");
exit(1);
}

 マニュアルのオプションの説明は、純粋にアルファベット順であるべきだ。これは、オプションが
引数を取る/取らないにかかわらない。また、大文字小文字の順で示すべきだ。

 現在、カーネルコードは、styleガイドに従うべきである。サードパーティによるモジュールや
ディバイスドライバのガイドラインは、より緩和的である。しかし、最低限内面的に
それらのstyleと矛盾しないようにすべきである。

 様式的な変化(空白の変化も含め)は、ソースリポジトリにとって重大であり、良い理由を除いて
避けなければいけない。リポジトリにおけるFreeBSD KNF style規則のコードは、コンプライアンス
から逸脱してはいけない。可能な時は、いつでもコードをコードチェッカー(lint(1)やgcc -Wall
にかけ、警告を最小限に減らすべきである。

#SEE ALSO#
 indent(1), lint(1), err(3), warn(3), style.Makefile(5)

#HISTORY#
 このマニュアルページのほとんどは、4.4BSD-Lite2 release の src/admin/style/styleの
ファイルに基づき、日々の更新は、現在のFreeBSDプロジェクトの要望と実践に反映されている。
src/admin/style/style は、Ken ThompsonとDenis RitchieのAT&T UNIX Version 6に
おけるプログラミング様式のCSRGである。