Cライブラリが同じ名前のマクロと関数を使用するのはなぜですか?


20

PJ Plaugerの「The Standard C Library」を読んでいますが、これは本当に興味深いです。この本では、ライブラリの使用方法だけでなく、ライブラリの実装方法についても説明しています。

ctype.hセクションを読み終え、ヘッダーで関数がマクロと関数の両方として宣言されています。例えば

int isdigit(int);

だけでなく

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

両方が使用される理由がわかりませんか?

また、独自のカスタムを再作成しようとすると ctypeヘッダーと実装とすると、マクロを削除する(定義をコメントアウトする)場合にのみ正常にコンパイルできます。

この側面は本で実際に説明されていませんでした。誰か説明してもらえますか?


コンパイラにマクロとして実装することを強制するC標準には何もありません。このマクロは、Cがインライン化されていなかった昔の残residueである可能性があります。ただし、スマートコンパイラは、明示的なインラインキーワードなしで、必要に応じてその関数をインライン化できる必要があります。そのため、関数のようなマクロは、コンパイラーを作成するのが得意ではない誰かによってコンパイラーが実装されたため、そこにしかありません。

回答:


23

マクロは関数呼び出しを伴わないため、(推定上)より効率的です。ポインターオフセットルックアップのみを含むため、より簡単に最適化できます。

関数呼び出しは、プログラムがマクロ定義なしでコンパイルされた場合でも、同じライブラリに対するリンクを可能にします-異なるヘッダーでコンパイルされた場合、またはソースファイル内の不正な宣言でコンパイルされた場合。たとえば、マクロを持たない誰かの「改善された」ctype.hのバージョンを持つコンパイラがある場合、関数は実行時に使用するためにまだ存在します。

標準を見ると:

7.1.4ライブラリ関数の使用

ヘッダーで宣言された関数は、ヘッダーで定義された関数のようなマクロとして追加で実装できるため、ヘッダーが含まれているときにライブラリ関数が明示的に宣言されている場合、以下に示す手法のいずれかを使用して、宣言がそのようなマクロの影響を受けます。関数の名前の後にマクロ関数名の展開を示す左括弧が続かないため、関数のマクロ定義は、関数の名前を括弧で囲むことでローカルに抑制することができます。同じ構文上の理由から、ライブラリ関数がマクロとして定義されている場合でも、ライブラリ関数のアドレスを取得することが許可されています。

つまり、次のように書くと:

int b = (isdigit)(c);

または

int (*f)(int) = &isdigit;
int b = f(c);

次に、マクロではなく、実際の関数を呼び出しています。法的に書くこともできます:

#undef isdigit
int b = isdigit(c);

または(#include <ctype.h>直接または推移的に持たないソースファイル内):

extern int isdigit(int);
int b = isdigit(c);

マクロ定義なしでプログラムをどのようにコンパイルできますか?
-user619818

extern int isdigit(int)たとえば、を使用して@ user619818 。
ecatmur

はっきりしているので、ユーザーは#include <whatever>を持たず、代わりにint isdigit(int)を追加します。実装ファイルの先頭。OK、応答を適切に読んでください。
-user619818

呼び出し可能な関数(インラインマクロコードに対して)を使用すると、pythonやperlなどの他の言語もこれらの関数とインターフェイスできます
テクノサウルス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.