ポータブルコードを書くために私が心に留めておくべきことは何ですか?私はC++の初心者なので、最初から練習したいと思っています。
ありがとう。
プラットフォーム固有のコードを再利用可能なコードとは別に、できれば別のファイルに、ただし少なくとも別の機能に保持します。 #if WIN32
と#if CYGWIN
と#if BSD
がいたるところにあり始めると、メンテナンスの悪夢が発生します。
次に、少なくとも2つの異なるプラットフォームで早期に頻繁にコンパイルします。一般的な選択肢は、WindowsではVisual C++、Linuxではgccです。システムライブラリもコンパイラも共有されていないため、設計に深く定着する前に、移植性のないコードを見つけることができます。
ポータブルコードを書くために私が心に留めておくべきことは何ですか?
最初にコマンドラインプログラムを作成します。準備ができたら、 Qt などのクロスプラットフォームウィンドウツールキットを見つけます。
多言語コードの記述に興味がある場合は、プラットフォーム固有のライブラリに依存するのではなく、 [〜#〜] icu [〜#〜] などのサードパーティのUnicodeライブラリを使用してください。
可能な場合はSTLタイプを使用してください。システム依存型とAPIの使用には注意してください。たとえば、WindowsではUINTやDWORDなどのタイプを使用しないでください。
Boostのようなライブラリを使用すると、移植可能なコードを簡単に作成できます。 GUIが必要な場合は、Qtのようなクロスプラットフォームツールキットの使用を検討してください。
プラットフォーム固有のコードを作成する必要がある場合があります。その場合は、次のようなことができます。
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
いくつかのガイドライン:
移植性を得るために、効率とパフォーマンスをトレードオフしなければならない場合があります。たとえば、コードでバッファー外のフィールドにアクセスする必要がある場合は、いつでもパック構造体をバッファーポインターにキャストできます。しかし、それはひどく移植性がありません。したがって、代わりに、オフセットで計算された名前付きポインターを使用する必要があります。境界調整処理コードを使用する場合もあります。きれいではありませんが、ポータブルです。幸いなことに、クラスインターフェイスを慎重に使用することで、そのようなものの多くを隠すことができます。
すべてのコードをそのように記述する必要はありません。明確に定義された責任の境界を使用して非常にモジュール化された方法でアプリケーションを設計する場合、コードの90〜95%を問題なく移植できます。次に、新しいプラットフォーム用にカスタマイズする必要がある非常にローカライズされた領域で5〜10%を分離します。
不注意なプログラマーは、分類を試みることができる多くの罠に陥る可能性があります。しかし、最初にあなたに言わせてください:絶対としてそれは不可能です。
問題は、特定のコンパイラの問題のために、標準に準拠したコードでさえ移植できない可能性があることです。
これが私の頭の中で考えることができる主なカテゴリーです。
コンパイラ拡張
たとえば、変数配列の使用のように:
void func(int const n)
{
int array[n];
}
これは標準ではありませんが、実用的であるため、多くのコンパイラがサポートしています。
標準ライブラリ拡張
多くの標準ライブラリの実装は、指定されたことのないstd::hash_map
を提供します。コードで使用する場合、移植性はありません。
現代の傾向は、このようなものをstd::tr1
名前空間に隠して、プログラマーがこれが拡張機能であることを認識できるようにすることです。
また、多くの場合、typedef
または汎用ではないマクロ(たとえば、PRETTY_FUNCTION
)を定義していることに注意してください。標準ではマクロは指定されておらず、typedefはほとんど指定されていません。
プラットフォーム固有
たとえば、int
またはdouble
のサイズと配置は標準で指定されていません。ビットをいじって32ビットになると予想する場合は、コンパイラを変更しなくても64ビットプラットフォームに夢中になります。
プラットフォームAPI
私たちのプログラムはコンパイルすることを目的としており、多くの場合、プログラムが実行されているコンピューターと対話することを目的としています。
クロスプラットフォームのポータブルAPIを見つけるか、独自のAPIを作成する必要があります。以下のリストでいくつかのライブラリを確認してください。
ライブラリ
よく書かれたライブラリのほとんどは移植性が高いので、以下をサポートしていることを確認してください。
優れたライブラリには次のものが含まれます。
あなたがレビューする必要がある他のもの...そしてそれは時間がかかります。
そこに完璧な答えはないと思います。ただし、完全な移植性はあり得ないため、サポートするコンパイラとプラットフォームを決定する必要があります。
プラットフォームの場合、Windowsと1つのLinuxフレーバーから始める必要があります。コンパイラーの場合は、任意の2つを選択します(余裕があればComeauを使用)。
他の人は前にそれを言いました、しかしここにそれについての私の見解があります:
1)C++が必要ですか?ベアメタルに近いため、ポータブルコードを作成するのに最適な言語ではありません。 Java、Python、Perl、PHPまたはJavascriptの方が適している場合があります。
2)C++が必要な場合は、完全に移植可能なコードを書き込もうとしないでください。とにかくほとんど不可能です。代わりに、サポートするプラットフォームを早期に決定してください。例:Linux、MacOS X、Windows
3)選択したすべてのプラットフォームでコードを継続的にテストするようにしてください。 Windowsでビルドするだけでなく、「完了したら」Linuxバージョンをコンパイルすることを期待してください。すべてのプラットフォームで毎日コンパイルし、問題がないかテストを続けてください。
可能であれば、少なくとも2つの異なるコンパイラを使用してすべてのコードをコンパイルします。
学習のために、1つの実装に集中する本を避けるようにしてください。場合によっては、導入部または初期の章で、言語実装を取得または使用する方法について説明します。複数の実装について言及している場合は、おそらく問題ありません。
プラットフォームに依存しない参考書を入手してください。 StroustrupのC++プログラミング言語は優れたリファレンスですが、初心者が学ぼうとするのに適した本ではありません。特定の実装の参照に依存しないでください。たとえば、MSDNは便利ですが、主な焦点はVisual C++を使用してWindowsプログラムを作成する方法であり、どこでもコンパイルして実行するプログラムを作成する方法ではありません。
本当に便利なものを書くには、移植性のないコードに取り掛かる必要があります。互換性が最も低くなるのは、ユーザーインターフェイスコードを他のすべてのものから分離する習慣を身に付けるようにしてください。プラットフォーム間で変更する必要のあるコードが少ないほど、コードの移植性が高くなります。
OSに依存しないコードは、C++では驚くほど実行が困難です。この些細な例を考えてみましょう。
_#include <iostream>
int main(int argc, char** argv) {
std::cout << argv[0] << std::endl;
}
_
これは完全に有効なC++ですが、WindowsではUnicodeコマンドライン引数を受け入れないため、移植性はありません。 Windowsの正しいバージョンは次のとおりです。
_#include <iostream>
int wmain(int argc, wchar_t** argv) {
std::wcout << argv[0] << std::endl;
}
_
もちろん、これも移植性がなく、Windowsでのみ機能し、標準ではありません。したがって、実際には、条件付きコンパイルに頼らずに、C++で移植可能なmain()
関数を作成することさえできません。
pOSIXシステムコールを使用することをお勧めします。そうすれば、スレッドを作成したり、ミューテックスやシグナルを使用したりするさまざまな方法に対処する必要がありません。
問題は、WindowsがPOSIXに完全に準拠していないことですが、次のような特定のPOSIX機能を実装するライブラリがあります。[1]: http://sourceware.org/pthreads-win32/