2009-04-09 14 views
18

私が維持しているアプリケーションでは、stdlibに影響を与えるファイル記述子の制限に関する問題が発生しました。この問題は、標準のlibの32ビット版にのみ影響します。32ビットプラットフォーム用の#ifdef

私は自分のコードの修正案を考案し、それを実装したいと思っていますが、32ビットの実行可能ファイル用にコンパイルするときだけです。コードが32ビットまたは64ビットのターゲット用にコンパイルされているかどうかを判断するために#ifdefすることができるプリプロセッサのシンボルは何ですか?

EDIT

申し訳ありませんが、言及しなかった、コードはほとんどがコンパイルのためにGCCを使用して、クロスプラットフォーム、Linuxでは、窓、Solarisおよびいくつかの他のUNIXフレーバーです。私がクロスプラットフォームで使用できるデファクトスタンダード?私はいくつかの定義「__ILP23」と「__LP64」彼らは働くことのように思える...議論hereを見つけた2

EDITは、UNIXプラットフォーム上の背景を説明しています。誰もこれらの定義を使用する経験はありましたか?これは使えるだろうか?

+0

プラットフォームによって異なります。異なるOSは異なる#defineを使用します。あなたが運が良ければ、Boostは携帯用のラッパーをどこかに隠しています。しかし、それ以外の場合は、プラットフォーム固有のものを確認するだけで済みます。途中でどのプラットフォームを実行していますか? – jalf

+0

質問を編集しました。コードは、主にAIX、HP-UX上で実行される部品を使用して、windows、solaris、linuxをターゲットにしています。 – veefu

+0

#if sizeof(int)== 64 – mmmmmmmm

答えて

15

普遍的な#if defが適切かどうかわかりません。 C++標準では、ほぼ確実に定義されていません。確かにプラットフォームspceficものがあります。

たとえば、Windows

#if _WIN64 
// 64 bit build 
#else 
// 32 bit build 
#endif 

EDIT OPは、これがために使用することができる普遍的なマクロはありません

Windowsおよび非WindowsのGCCを使用し、他のコンパイラとの間でクロスコンパイルで言及はすべてのプラットフォームとコンパイラプリプロセッサの魔法の少しは、トリックを行うことができます。あなたがx86とamd64チップでしか作業していないとすれば、以下のことがこのトリックを行うべきです。他のプラットフォームでも簡単に拡張できます。

#if _WIN64 || __amd64__ 
#define PORTABLE_64_BIT 
#else 
#define PORTABLE_32_BIT 
#endif 
+0

これは、Chrisのコメントごとにいくつかのgcc調査と組み合わされているようです。あなたの両方を+1してください。 – veefu

4

よく知られているタイプを確認できます。 32ビットプラットフォームではsizeof(int *)== 4です。

のsizeofはコンパイル時知られているように私は

if(sizeof(int*) == 4) 
{ 
    ... 
} 

トリック

編集すればいいと考えている:コメントは正しいです、あなたは#if指令が動作しません、場合定期的に使用する必要があります。

C++を使用している場合テンプレート化されたコードを作成して、sizeof()呼び出しに基づいてコンパイラーに特殊化を選択させることができます。 32ビットプラットフォーム用にビルドする場合、コンパイラは32ビットプラットフォームのコードをインスタンス化するだけです。 654ビットのプラットフォーム用にビルドする場合、コンパイラは64ビットプラットフォームのコードをインスタンス化するだけです。

+0

これは#ifdefに対しては機能しません。 #ifはコンパイル時間ですが、#ifはプリプロセッサ時間 – JaredPar

+0

で無効なコードです(VS2008でテスト済み) – JaredPar

+0

同意します。 OS X LeopardのGCC 4.0.1でテストされています。 –

13

であると考えています。誰も答えはありませんが、それは確かにあなたが始めるのを助けることができます。

EDIT:__i386__を使用して32ビットx86チップをチェックすることができます。__X86_64__などの64ビットx86チップをチェックすることをお勧めします。 (注:__ia86__を含む以前の回答は実際には64ビットx86チップではなく、別のチップであることがわかりました。これはハードウェアの経験が不足していることを示しています。 GCCのバージョン間でかなり普遍的でなければなりません。

+0

通常のintel64ビットコンパイルで__ia64__は真となりますか?または__ amd64__などがありますか? – JaredPar

+0

64ビットアーキテクチャー(またはインテル以外のアーキテクチャーでのプログラミング)に関する経験はありませんが、predefsページによれば、64ビットAMD用の__amd64__があります。 __ia64__はx86固有のようです。 –

+0

__i386__はintel cpu用にコンパイルするときにのみ正しく動作しますか? solarisでは、sparc-s2用にコンパイルします。 – veefu

1

OSやコンパイラによって異なりますが、実装上の決定です。

0

C++標準で定義されているようなシンボルはありません - 特定のプラットフォーム(質問に指定していない)が提供する可能性があります。

2

私がやっているのはおそらくMakefile内で、あなたが32ビットプラットフォームであるか64ビットでunameを使っているかを判断します。次に、CFLAGS、-DX32、または-DX64に追加します。あなたは#ifdef X64しかできないでしょう。

しかし、これは単なる解決策です。私は窓で何をするのか分かりません。

+0

その問題は、コンパイルに使用されているシステムが64ビットであっても、32ビットの実行可能ファイルをコンパイルしている可能性があります。しかし、あなたはこの情報が何らかの形でメイクファイルに公開されている必要があります。 32または64がターゲットにされているかどうかをコンパイラに伝える必要があります。それに適応できるはずです。 – veefu

6

はそのを見てください:構造はunsigned char型のフィールドにファイルディスクリプタを格納するため、

i386 macros
AMD64 macros

+0

そこに良い情報、ありがとう。 – veefu

2

少なくとも32ビットSolarisは、256のファイルポインタの制限があります。これは、SunOSのほぼ不可能な古いバージョンとの下位互換性のために保持されています。他のプラットフォーム - 私は他のほとんどのプラットフォームを言いたくて、その制限を共有していません。一方、通常のユーザプログラムでは、同時に多数のファイルを開く必要があるのは比較的珍しいことです。バグを示していることが多い(終了時にファイルを閉じるのではなく)。しかし、それは同時に多くのデータファイルを開く必要があるデータベースサーバのようなものにとっては問題になる可能性があると言いました。


一つのコメントが書かれています:

ほとんどそれだこと。多数のファイルを開く必要はありませんが、サーバーはクライアントからの多数の接続を処理します。ソケットハンドルとファイルディスクリプタは同じ場所から来ているようです。システムレベルの呼び出しが返ってfd> 255を返すため、 'fopen'は失敗します。

「ソケットハンドル」はシステムコールレベルのファイル記述子なので、同じ場所から来ていますファイルの通常のファイル記述子として使用します。

これを回避する必要がある場合は、現在のソケットオープンコードをラップして、ファイルディスクリプタが0..255の範囲になるように 'dup2()'を呼び出してファイルディスクリプタを作成します。 stdioが使用しない範囲 - 元のファイル記述子を閉じます。これは、dup2が対象のファイル記述子が現在オープンしている場合、メリハリで閉じるため、利用可能なファイル記述子を追跡する必要があることだけです。

もちろん、私はあなたのソケットコードがファイル記述子を読み込み、ファイルポインタは読み込まないと仮定しています。その場合、より大きな問題があります。同じリソースを使いたいことが多すぎると同時に、それらをすべて同時に使用することはできません。

+0

それはほとんどそれです。多数のファイルを開く必要はありませんが、サーバーはクライアントからの多数の接続を処理します。ソケットハンドルとファイルディスクリプタは同じ場所から来ているようです。我々は多くの接続があると、システムレベルの呼び出しが返され、fd> 255であるため 'fopen'が失敗します。 – veefu

+0

+1、洞察力があります。 – veefu

+0

はい、それは私が実装したものとほぼ同じです。 へのラップされた呼び出しと、 '<255>のときハンドルを複製する' fcntl 'を呼び出すコードで' accept 'これは正常に機能しますが、必要なプラットフォームに分離する必要があります。したがって、#ifdefに関する質問。 – veefu

1

私はWindows用のこのような工事を使用します。

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_M_IX86) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif 

バーサス:旧ソリューションで

 
#if defined(_WIN64) 
    // 64 bit code 
#else 
    // 32-bit code 
#endif 

、#エラーのコンパイラはあなたが必要な場所を教えてくれことができるようになりますので、新しいプラットフォーム用のコードを追加するこれにより、64ビットでも32ビットでもないプラットフォームに遭遇した場合でも、メンテナンス性が向上します。はい、_M_IX86は32ビットと全く同義ではありませんが、ほとんどの私たちがサポートしている唯一の32ビットプラットフォームはx86です。実用的な手段として十分です。

次の解決策では、grepなどを使用して、新しいプラットフォーム用のコードが必要な場所を手動で把握する必要があります。これは面倒でエラーが発生しやすいです。

次のような構成も許容されますが、実稼働環境でテストしたり、実際には非常に考えていません。

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_WIN32) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif