2012-09-24 3 views
8

コンパイラに埋め込み型として特定の型(ex。ptrdiff_t)がある場合は、再度型定義する必要はありません。私は以下のコードが私が期待した通りに正しく動作しないことを知っています。私は特定のタイプがすでにCコンパイラで定義されて確認することができますどのようにCコンパイラで特定の型がすでに定義されていることを確認する方法はありますか?

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t; 
#endif 

+1

具体的なケースではptrdiff_tは、stddef.hをインクルードすると常に定義されます。 –

+2

特定の定義の存在とプロパティをコードでテストできることを「リフレクション」といいます。スクリプト言語は完全な反映をサポートする傾向があります。これは、言語を記述することが比較的簡単であることもあります。 .NETとJVMはリフレクションもサポートしています。しかし、ネイティブ言語の場合、実行時リフレクションをサポートするには、余分な実行可能コードが必要です。そのオーバーヘッドなしでコンパイル時のリフレクションをサポートすることもできますが、Cはコンパイル時でも実質的にリフレクションをサポートしていません。 – Steve314

+0

cmakeやautotoolsのようなツールを使用する – szx

答えて

1

あなたは2つの異なるものを混乱ビットです:

intfloatのように、種類に建てられたが、これらはSTND種類があり、それらが定義されているなどして、すべてのコンパイラです。 __int64のような型は標準ではありませんが、いくつかのコンパイラで定義されています。それらを使用するために何もする必要はありません。同時に、定義されているかどうかをコード内で把握することはできません。これは、コンパイラのドキュメントからのみ考え出すことができます。あなたは書くことができます:

#ifdef MSVC 
     .... Microsoft specific code 
#else 
     .... Code for other compiler. 
#endif 

このアプローチは、あなたがcompiler independent environmentのようなものを作成することができます。

組み込み型以外にも、ヘッダーからの型があります。いくつかのヘッダは次のような構造を持っています:

#ifndef ptrdiff_t_DEFINED 
    #define ptrdiff_t_DEFINED 
    typedef long int ptrdiff_t; 
#endif 

マクロプロセッサdefnは、その型のdefnから離れていることに注意してください。型が定義されているかどうかは確認できませんが、定義が定義されているかどうかは簡単に確認できます。

自分のコードに含まれるヘッダーはどれですか?つまり、これらの定義はin the compiler itselfではありません。それらは現在の翻訳単位の定義に含まれています。コンパイラの場合は、独自のコードで記述する他の型定義とほとんど違いがありません。

上記の例のように "defarding defns"を持たないコンパイラまたはシステムヘッダーがあります。この場合、あなたが行うことができる唯一のことは、どのヘッダーが来ているかを追跡し、これらのヘッダーを含める/含まないことです。#includeステートメントの周りに#ifdefガードを使用しています。

5

一般的にその方法はありません。場合によっては、使用できるタイプと同時に定義されたマクロが存在することがあります。

具体的な例では、#include <stddef.h>とすることができます。これは常にptrdiff_tを定義する必要があります。

0

C言語で予約された構文を再定義すると、一般にコンパイル時にエラーが発生するため、一般的にチェックすることはできません。 学習/学習プロセスに興味がある場合は、Cプログラムの例外/エラーをチェックして、タイプが予約されているかどうかを検出するための基本的なコンパイラ・パスを書くことができます。あなたの質問に

4

他の人が言っているように、これに対する良い一般的な解決策はありません。型名はプリプロセッサには見えないので、その存在をテストするのに#ifdefを使うことはできません。

ただし、いくつかの部分的な解決策があります。それらは、特定のタイプの要件がどこから来たかによって異なります。

1990年、1999年、および2011年に発行されたISO C標準のいくつかのバージョンがあります。各新しい標準(理論上)は前のものに取って代わるものであり、それぞれ新しい標準がいくつか定義されています。たとえば、1999 Cの標準では、<stdbool.h><stdint.h>のタイプが追加され、bool,int32_tなどのタイプが追加されています。boolタイプを使用したいが、C99をサポートしていない実装にコードを移植したい場合は、以下のような:

#if defined(__STDC__) && __STDC_VERSION__ >= 199901L 
#include <stdbool.h> 
#else 
typedef enum { false, true } bool; 
#endif 

enumタイプは正確 C99の組み込みboolタイプのように動作しませんので、あなたは、あなたがそれを使用する方法に少し注意する必要があります。

タイプuintptr_tは、<stdint.h>で定義されています。情報を失うことなく変換されたvoid*ポインタ値を保持できる符号なしタイプです。そのような符号なしの型を持たない実装(たとえば、ポインタがどの整数型よりも大きいため)は、それを提供しません。あなたは、直接型自体をテストすることはできませんが、その境界を与えるマクロをテストすることができます

#include <stdint.h> 

#ifdef UINTMAX_MAX 
/* uintmax_t exists */ 
#else 
/* uintmax_t doesn't exist */ 
#endif 

あなたはC99を仮定することができない場合__STDC____STDC_VERSION__のための試験でこれをラップする必要があるかもしれませんより良い。

タイプlong longは、C99で定義されたタイプ(ライブラリの一部ではありません)です。ここでも、あなたは直接それをテストすることはできませんが、その境界を定義するマクロをテストすることができます

#include <limits.h> 

#ifdef LLONG_MAX 
/* long long exists */ 
#else 
/* long long *probably* doesn't exist */ 
#endif 

は最後に、あなたがCで直接行うことができないものがありますが、あなたはのように行うことができますあなたのプログラムのビルドプロセスの一部。例えば、POSIXは、POSIX固有のヘッダ<unistd.h>(これは、getpid()関数によって返されるプロセス識別子の型です)にタイプpid_tを定義します。あなたは条件付きでヘッダーを含めることはできません - しかし、あなたは、ヘッダーが存在しない場合、コンパイルに失敗する小さなプログラム書くことができます。

#include <unistd.h> 
pid_t dummy; 

は、ビルドプロセスの一環として、このファイルをコンパイルしようとします。成功した場合は、コンフィグレーションヘッダに

#define HAVE_PID_T 

のような行を追加します。それが失敗した場合、あなたのソースコードで

#undef HAVE_PID_T 

のような行を追加し、あなたはその後のようなものを書くことができます。

#include "config.h" 
#ifdef HAVE_PID_T 
#include <unistd.h> 
/* pid_t exists */ 
#else 
/* pid_t doesn't exist */ 
#endif 

GNU Autoconfは、この種の試験を自動化する方法を提供し、それがために批判されています過度に複雑で扱いにくい。

これは、タイプが存在するかどうかを判断したら、その情報に役立つ何かを行うことができることを前提としています。 boolのようなタイプの場合は、ほぼ同等の方法を実装できます。一方、pid_tでは、プロセスを扱うすべてのコードを単に#ifdefにしない限り、良いフォールバックはない可能性があります。あなたのプログラムがpid_tgetpid()を持たないシステムで動作しない場合は、それらが存在することを前提としたコードを書くのが最善でしょう。コードを提供していないシステムでコードをコンパイルしようとすると、すぐにコンパイルが失敗し、それがあなたができる最善の方法かもしれません。

関連する問題