acl4のページ0001
(1)
#if (!defined(a_DbgLv))
#define a_DbgLv 2
#endif
#if (!defined(a_Version))
#define a_Version 1
#endif
#if (a_DbgLv < 2)
#define _argDef_
#define _argDef
#define _arg_
#define _arg
#else
#define _argDef_ const char *a_fil, int a_lin,
#define _argDef const char *a_fil, int a_lin
#define _arg_ __FILE__, __LINE__,
#define _arg __FILE__, __LINE__
#endif
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if (a_Version >= 1)
#define static_ a_static
#define class_ a_class
#define DbgLv a_DbgLv
#endif
#if (!defined(a_static))
#define a_static static
#endif
#define a_class(nam) typedef struct nam ## _ nam; struct nam ## _
#if (a_Version >= 1)
#define errExit a_errExit
#endif
a_static void a_errExit(const char *f,...)
{
va_list ap;
va_start(ap, f);
vfprintf(stderr, f, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
(2)
- 命名規則:
- acl4ライブラリが提供するものについては、a_という接頭語をつけています。だからこれを避ければ、他とぶつかることはありません。
- ただし a_Version というマクロ定数の値によっては、接頭語なしのエイリアスを定義する場合もあります。
- staticのようにa_を外すと既存のC言語のキーワードとぶつかる場合は、末尾に _ を追加してエイリアスを定義しています。
- _arg など:
- 何のことかよくわからないと思いますが、a4_0002以降で活躍します。その時に説明します。
- たくさんのinclude:
- 標準関数がすぐに使えるように、たくさん include しています。
- a_staticは何のため?:
- acl4ではほぼすべての関数を static で宣言します。なぜなら static で宣言された関数を使用しなければ、それはアセンブラに出力されないからです。
- これで「使わない関数が実行ファイルに入っている」という事態を避けることができます。
- でも分割コンパイルなどをするとかで、staticをつけないで宣言したい場合もあり得ます。そういう時はこの a_static を空文字列で宣言しておけばいいのです。そうすれば static なしで宣言できるわけです。
- a_classは何のため?:
- structしてからtypedefするのが、面倒だなーって思ったのです。a_classを使えば、typedefもやってくれます。a4_0002に使用例があるので、そのときに説明します。
- a_errExit()は何をするの?:
- エラーメッセージをstderrに出力して、exit(1)します。まあそれだけの関数なのですが、これがあるとエラー処理が書きやすくなるので好きなのです。
- 改行もしてくれるので、エラーメッセージの末尾の改行を書かなくていいのです(ちょっとだけプログラムが短くなる!)。
(3) 使い方
- acl4ライブラリは以下のようにして利用します。
- [1]まずa4_0001のプログラムを"acl4.c"として保存します。
- [2]次にacl4を使ったプログラムを書きます。
- [3]コンパイル時に、"acl4.c"のあるパスをインクルードパスの一つとして指定します。
- 以下のコードでやってみます。"t0001a.c"とします。
#define a_Version 1
#include <acl4.c>
int main(int argc, const char **argv)
{
if (argc < 2) errExit("usage>t0001a file-path");
FILE *fp = fopen(argv[1], "rt");
if (fp == NULL) errExit("fopen error: %s", argv[1]);
for (;;) {
int c = fgetc(fp);
if (c == EOF) break;
putchar(c);
}
fclose(fp);
return 0;
}
(4) Q&A
- [Q:00]なぜ.hファイルではなく.cファイルなのですか?
- [A:00].hファイルにするのは分割コンパイルをする場合だと思います。分割コンパイルの場合、コンパイラはそれぞれのファイルごとに最適化することしかできません。この関数はインライン展開してしまおうとか、そういうことはできず、どんな短い関数も普通の関数呼び出ししか選択できなくなります。
- またacl4ライブラリはマクロ定数によってコード内容が大きく変わります(a4_0002以降は特にそうです)。そういうライブラリの場合、分割コンパイルはあまりメリットがありません。だから.cファイルとして全部一気にコンパイルしてもらうようにしています。
- コンパイラの負担は増えますが、最近のコンパイラは非常に優秀な上にメモリがたくさんあるので、こんな方法でも十分に実用的な速度でコンパイルできます。
- [Q:01]acl4ライブラリについて感想や意見を言いたいのですが、どこに書けばいいですか?
- [A:01]「osdev-jp / Discord / k-tanの個人チャンネル / acl4 : C言語でもここまでできる」でお待ちしております!
(99) 更新履歴