fc2ブログ

C99に対応した標準Cライブラリの実装レポートを行っていきます。

プロフィール 

高木信尚

Author:高木信尚

ホームページ
ブログ

最近の記事 

最近のコメント 

最近のトラックバック 

月別アーカイブ 

カテゴリー 

ブロとも申請フォーム 

この人とブロともになる

ホーム 全記事一覧

 

C99からは、C言語にも真理値型が導入されました。本来であれば、その型名はC++と同じ「bool」にしたかったのでしょうが、既存のソースコードの多くは、「bool」型を独自に定義していたため、混乱を避けるために、予約済み識別子であった「_Bool」が真理値型を表す予約語となったようです。

ところが、やはり使い勝手からすると「_Bool」より「bool」の方がよいので、「bool」を使えるようにするために用意されたのが<stdbool.h>です。今回は、この<stdbool.h>についてです。

まず、標準Cライブラリが提供する「bool」(および「true」、「false」)が使用されているかどうかを判別するためのマクロを定義しなければなりません。そのマクロは、__bool_true_false_are_definedです。今回は、このマクロを二重インクルードガードの目的にも流用します。したがって、

#ifndef __bool_true_false_are_defined
#define __bool_true_false_are_defined
/* 内容 */
#endif

というのが、ヘッダの枠組みになります。

次に、boolマクロを定義します。boolをtypedef名ではなくマクロとしているのは、typedef名にすると、ブロック有効範囲内で同名の識別子が再定義されてしまうためかと思われます。

#define bool _Bool

そして最後に、真理値定数であるtrueおよびfalseをマクロ定義します。

#define true 1
#define false 0

C++とは異なり、trueおよびfalseは単なるint型になります。これは、否定演算子、等価演算子、関係演算子の結果が、C++ではbool型であるのに対して、C99ではint型であることにも関係していると思われます。


▽続きを読む▽
2006/01/26 12:35|その他のライブラリTB:0CM:0

 

地味な記事が続いていますが、今回お話しする<stdarg.h>で、C95のフリースタンディング環境で必要な標準Cライブラリは全てそろうことになります。この後は、もう少し地味なものが続きますが、C99のフリースタンディング環境で必要なヘッダを済ませてから、C90→C95→C99と実装を進めていきたいと思います。

まずは、va_list型の定義からです。このva_list型をどんな型にするかは、関数のコーリングコンベンションと深く関わります。参考までに"h8300-hms"ターゲットのコーリングコンベンションについて書かれたページをご紹介しておきます。

実際には、gccには<stdarg.h>の中の型やマクロの定義は、ビルトイン定義されているようです。

typedef __builtin_va_list va_list;

マクロに関しても同様です。

#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)

そして、C99で追加されたもう一つのマクロ、va_copyも同様です。

#define va_copy(d, s) __builtin_va_copy(d, s)


▽続きを読む▽
2006/01/25 20:51|その他のライブラリTB:0CM:0

 

さて、準備ばかりでも退屈なので、そろそろ実際の実装に入っていきたいと思います。といっても、最初は、標準Cライブラリの中でも最もくだらない<iso646.h>です(準備以上に退屈かもしれません)。こういうくだらないものは最初に片付けておいて、楽しみは後に取っておくことにしましょう。

<iso646.h>は、ISO-646のように、C言語の基本ソース文字集合として必要な文字を欠いている文字コードを使わざるを得ない処理系のための代替表現マクロを定義するものです。言葉にすると、何か難しいのですが、要するにこのヘッダを使うことは実際にはまずありません。

用途としては、このヘッダは全くの役立たずですので、今回は<iso646.h>を題材として、ヘッダを記述する上での作法を解説したいと思います。

まず、最初にお断りしておかなければならないのですが、C言語の標準規格では、標準ヘッダはファイルであるとは限りません。#include指令を使ったときに、必要な宣言や定義がなされたものとして扱うだけで、実際にはファイルを取り込まないような実装でも構わないわけです。

しかし、そのような処理系では、標準ライブラリを自作することができません。gccをはじめ、ほとんどの処理系ではヘッダはファイルとして実現されています。今回の実装でも、それを前提として進めていきたいと思います。

まず、ヘッダを記述する際には、そのヘッダを複数回インクルードされても、一度しか内容が取り込まれないようにするために、二重インクルードガードを施します。具体的には次のようにします。

#ifndef _ISO646_H
#define _ISO646_H

/* ヘッダの内容 */

#endif

これは、最初にインクルードされたときには、まだ_ISO646_Hマクロが定義されていませんから、ヘッダの内容はそのまま反映されます。しかし、初回のインクルード時に、2行目の#define指令で_ISO646_Hマクロが定義されますので、再びこのヘッダをインクルードしようとしても、1行目の#ifndef指令によって除去されます。

ここで注意点が二つあります。

まずは、_ISO646_Hというマクロ名です。このマクロ名を具体的にどんな名前にするかという決まりはありませんが、下線(アンダースコア)で始まり、大文字が続いていることが重要なのです。あるいは二重の下線から始まってもかまいませんが、二重の下線で始まる名前はC++コンパイラが内部的に使っている場合があるので、避けた方が無難です。

下線で始まり、下線または大文字が続く識別子は「予約済み識別子」と呼ばれます。予約済み識別子は、コンパイラと標準ライブラリに予約されているため、ユーザーが定義することはできません(定義した場合の動作は未定義です)。

今回は、標準ライブラリの実装ですから、規格で定められた識別子以外はユーザーに開放しなければなりません。したがって、通常とは逆に、ライブラリが内部的に使用する識別子は、全て予約済み識別子でなければなりません。

もう一つの注意点は、ファイルの末尾にあります。#endifの後ですが、ここは必ず改行文字がなければなりません。空でないソースファイルが改行文字で終わらなかった場合の動作は未定義だからです。

未定義の動作というのは、何も実行時だけのものではありません。コンパイル時の動作にも関わるのです。すなわち、コンパイルエラーが発生するならまだよいのですが、何事もなかったかのようにコンパイルが完了し、でたらめなコードを生成していても、文句は言えないのです。

▽続きを読む▽
2006/01/24 00:11|その他のライブラリTB:0CM:0

ホーム 全記事一覧

ブログ内検索 

お勧め書籍 

RSSフィード 

リンク 

このブログをリンクに追加する

Copyright(C) 2006 TAKAGI Nobuhisa All rights reserved.
Powered by FC2ブログ. template designed by 遥かなるわらしべ長者への挑戦.