12

コンパイラが埋め込み型として特定の型(例:ptrdiff_t)を持っている場合、それを再度typedefしたくありません。以下のコードが期待どおりに正しく機能しないことを私は知っています。

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t;
#endif

特定の型がCコンパイラですでに定義されていることを確認するにはどうすればよいですか?

4

4 に答える 4

6

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

あなたの特定の例では、あなたはそうすることができます#include <stddef.h>、そしてそれは常にptrdiff_tを定義するべきです。

于 2012-09-24T03:42:52.527 に答える
6

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

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

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

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

この型はC99の組み込み型とまったく同じenumように動作しないため、使用方法に少し注意する必要があります。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は、pid_tPOSIX固有のヘッダーでタイプを定義します<unistd.h>(これは、関数によって返されるプロセス識別子のタイプですgetpid())。条件付きでヘッダーを含めることはできませんが、ヘッダーが存在しない場合にコンパイルに失敗する小さなプログラムを作成することはできます。

#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_tプログラムがとを持たないシステムで動作しない場合はgetpid()、それらが存在することを前提としたコードを記述するのが最善の場合があります。コードを提供していないシステムでコードをコンパイルしようとすると、すぐにコンパイルに失敗します。これが最善の方法かもしれません。

于 2012-09-24T20:51:53.270 に答える
2

あなたの質問では、2つの異なることを少し混乱させています:

int、などの組み込み型がありますfloat。これらは標準型であり、すべてのコンパイラで定義されています。のようなタイプ__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

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

自分で決めるコードに含まれるヘッダー。これは、これらの定義がではないことを意味しますin the compiler itself。それらは、現在の翻訳単位の定義のセットに含まれています。コンパイラーの場合、独自のコードで作成する他の型定義とほとんど違いはありません。

上記の例のように、一部のコンパイラまたはシステムヘッダーには「保護定義」がありません。この場合、あなたができる唯一のことは、どのヘッダーから来ているのかを追跡し、これらのヘッダーを含める/含めないことです。mabyはステートメントの#ifdef周りに独自のガードを使用します。#include

于 2012-09-24T05:39:12.130 に答える
0

C言語の予約済み構造を再定義すると、通常、コンパイル時エラーが発生するため、一般的にチェックすることはできません。(アカデミック/学習プロセスに)興味がある場合は、基本的なコンパイラパスを記述して、Cプログラムの例外/エラーをチェックし、型が予約されているかどうかを検出できます。

于 2012-09-24T04:07:54.817 に答える