私が管理しているアプリケーションで、stdlibに影響を与えるファイル記述子の制限に関する問題が発生しました。この問題は、標準ライブラリの32ビットバージョンにのみ影響します。
私は自分のコードの修正を考案し、それを実装したいと思っていますが、32ビットの実行可能ファイル用にコンパイルする場合に限ります。コードが32ビットまたは64ビットのターゲット用にコンパイルされているかどうかを判断するために#ifdefで使用できるプリプロセッサシンボルは何ですか?
[〜#〜]編集[〜#〜]
申し訳ありませんが、コードはクロスプラットフォーム、Linux、Windows、Solaris、およびその他のいくつかのUNIXフレーバーであり、主にコンパイルにGCCを使用しています。クロスプラットフォームで使用できるデファクトスタンダードはありますか?
編集2
「__ILP23」と「__LP64」の定義が機能しているように見えることがあります...ディスカッション ここ unixプラットフォームの背景について説明しています。誰かがこれらの定義を使用した経験がありますか?これは使えるのでしょうか?
適切なユニバーサル#ifdefがあるかどうかはわかりません。 C++標準ではほぼ確実に定義されていません。確かにプラットフォーム特有のものがあります。
たとえば、Windows
#if _WIN64
// 64 bit build
#else
// 32 bit build
#endif
[〜#〜] edit [〜#〜] OPは、これはGCCおよび他のコンパイラを使用したWindowsと非Windows間のクロスコンパイルであると述べました
すべてのプラットフォームとコンパイラに使用できるユニバーサルマクロはありません。プリプロセッサの魔法の少しは、トリックを行うことができますが。 x86チップとAMD64チップのみで作業していると仮定すると、次の方法でうまくいくはずです。ただし、他のプラットフォームにも簡単に拡張できます
#if _WIN64 || __AMD64__
#define PORTABLE_64_BIT
#else
#define PORTABLE_32_BIT
#endif
predefSourceForge をブックマークすることをお勧めします。答えは1つではありませんが、それは確かにあなたが始めるのに役立ちます。
編集:GCCのみのコードの場合、__i386__
を使用して32ビットx86チップをチェックできます。__X86_64__
または64ビットx86チップをチェックするのと同様のものを試すことをお勧めします。 (注:__ia86__
に関する以前の回答は、実際には64ビットx86チップではなく、別のチップであることに気付きました。これは、ハードウェアの経験が不足していることを示しています。私よりもハードウェアに精通している人にとっては、上記にリンクしている事前定義されたマクロのSourceForgeページを参照してください。私よりもはるかに正確です。)動作するものは他にもいくつかありますが、これら2つはGCCバージョン間でかなり普遍的です。
よく知られているタイプのサイズを確認できます。 sizeof(int *)== 32ビットプラットフォームの場合は4。
Sizeofはコンパイル時に知られているので、私は
if(sizeof(int*) == 4)
{
...
}
トリックを行う必要があります
編集:コメントは正しいです。通常のif、#ifが機能しない場合は使用する必要があります。
C++を使用している場合テンプレート化されたコードを作成し、sizeof()呼び出しに基づいてコンパイラーに特殊化を選択させることができます。 32ビットプラットフォーム用にビルドする場合、コンパイラは32ビットプラットフォーム用のコードのみをインスタンス化します。 654ビットプラットフォーム用にビルドする場合、コンパイラは64ビットプラットフォーム用のコードのみをインスタンス化します。
最大ポインタ値定数を使用して、間接的にテストします。
#include <stdint.h>
#if UINTPTR_MAX == 0xffFFffFF
// 32-bit platform
#Elif UINTPTR_MAX == 0xffFFffFFffFFffFF
// 64-bit platform
#else
#error Unknown platform - does not look either like 32-bit or 64-bit
#endif
このように、アーキテクチャのプラットフォーム固有の定義に依存するのではなく、特定のアーキテクチャを持つことの直接的な結果、つまりポインタサイズに依存します。
構造体はファイル記述子をunsignedcharフィールドに格納するため、少なくとも32ビットのSolarisには256個のファイルポインタの制限があります。これは、ほとんど不可能なほど古いバージョンのSunOSとの下位互換性のために保持されています。他のプラットフォーム(他のほとんどのプラットフォームと言いたくなります)は、その制限を共有していません。一方、通常のユーザープログラムでは、多数のファイルを同時に開く必要があるのは比較的珍しいことです。多くの場合、バグ(ファイルが終了してもファイルを閉じない)を示します。とはいえ、データベースサーバーのように、同時に大量のデータファイルを開く必要がある場合は問題になる可能性があります。
1つのコメントは言う:
それはほとんどそれです。開いているファイルの数は多くありませんが、サーバーはクライアントからの多数の接続を処理します。ソケットハンドルとファイル記述子は同じ場所から来ているようです。多くの接続がある場合、システムレベルの呼び出しが返され、fd> 255であるため、「fopen」は失敗します。
「ソケットハンドル」はシステムコールレベルのファイル記述子であるため、ファイルの通常のファイル記述子と同じ場所から取得されます。
これを回避する必要がある場合は、現在のソケットオープニングコードをラップして、0..255の範囲のファイル記述子を取得すると、「dup2()
」を呼び出してファイルを作成する必要があります。 stdioが使用しない範囲の記述子-次に、元のファイル記述子を閉じます。これに関する唯一の問題は、dup2
が現在開いている場合、ターゲットファイル記述子を陽気に閉じるため、使用可能なファイル記述子を追跡する必要があることです。
もちろん、ソケットコードはファイルポインタではなくファイル記述子を読み取ると想定しています。その場合、より大きな問題が発生します。同じリソースを使用したいものが多すぎて、すべてを同時に使用することはできません。
私がおそらくやることになるのは、Makefile内で、32ビットプラットフォームを使用しているか、unameを使用して64ビットを使用しているかを判断することです。次に、CFLAGS、-DX32、または-DX64に追加します。 #ifdefX64だけでいいのです。
しかし、これは単なる一義的な解決策です。 Windowsで何をするかわかりません。
私はWindows用に次のような構造を使用しています。
#if defined(_WIN64) // 64ビットコード #Elifdefined(_M_IX86) // 32ビットコード # else #error "不明なプラットフォーム" #endif
対:
#if defined(_WIN64) // 64ビットコード #else // 32ビットコード #endif
前者のソリューションでは、#errorが原因で、コンパイラは新しいプラットフォームのコードを追加する必要がある場所を通知できます。これは、64ビットでも32ビットでもないプラットフォームに遭遇した場合の保守性を支援します。はい、_M_IX86は32ビットと完全に同義ではありませんが、私たちのほとんどがサポートしている32ビットプラットフォームは実際にはx86だけだと思います。したがって、実際的な対策としてはそれで十分です。
後のソリューションでは、grepなどを使用して、新しいプラットフォームのコードが必要な場所を手動で把握する必要があります。これは面倒でエラーが発生しやすいです。
私は本番環境でテストしたことも、あまり考えたこともありませんが、次の構造も許容できると思います。
#if defined(_WIN64) // 64ビットコード #Elifdefined(_WIN32) // 32ビットコード # else #error "不明なプラットフォーム" #endif
OSとコンパイラによって異なりますが、これらは実装の決定です。
定義は_WIN64だと思います
C++標準で定義されているそのようなシンボルはありません。特定のプラットフォーム(質問で指定していない)がシンボルを提供する場合があります。