web-dev-qa-db-ja.com

C ++でポータブルコードを書く方法は?

ポータブルコードを書くために私が心に留めておくべきことは何ですか?私はC++の初心者なので、最初から練習したいと思っています。

ありがとう。

28
understack
  • 標準ライブラリの使い方を学ぶ
  • 本を読む(例 これ
  • 経験を積んだら、使い方を学びましょう boost
17
Alexandre C.

プラットフォーム固有のコードを再利用可能なコードとは別に、できれば別のファイルに、ただし少なくとも別の機能に保持します。 #if WIN32#if CYGWIN#if BSDがいたるところにあり始めると、メンテナンスの悪夢が発生します。

次に、少なくとも2つの異なるプラットフォームで早期に頻繁にコンパイルします。一般的な選択肢は、WindowsではVisual C++、Linuxではgccです。システムライブラリもコンパイラも共有されていないため、設計に深く定着する前に、移植性のないコードを見つけることができます。

14
Ben Voigt

ポータブルコードを書くために私が心に留めておくべきことは何ですか?

  1. いくつかのコンパイラを近くに置き、ターゲットプラットフォームで定期的にコードをテストします。 Windows Windows/Linux用のクロスプラットフォームソフトウェアを使用している場合は、mingw、Visual Studio Express(つまり、「Microsoftコンパイラ」)、およびg ++を使用したLinuxインストール(または仮想マシンを使用)を維持してください。コードが完璧であっても、コンパイラーには予期しない癖があるかもしれません。たとえば、msコンパイラの特定のバージョンには、文字列定数のサイズに制限がありますが、gccにはありません。
  2. 標準タイプのサイズに依存しないでください。たとえば、msvcではsizeof(wchar_t)は2バイトです。 Linuxのインストールでは、4バイトになる可能性があります。 sizeofを使用するか(必要な場合)、コードで任意のタイプのsizeを使用する必要がないようにしてください。また、ポインターのサイズが4バイトであると想定しないでください(ユーザーデータポインターをAPI呼び出しシナリオに渡す)-64ビットで8バイトになります。
  3. コンパイラ固有のプラグマ、マクロ、および拡張機能は使用しないでください。たとえば、「#pragmaonce」は避けてください。
  4. 標準ライブラリ(コンパイラ開発者が提供)の拡張機能を使用しないでください。ただし、これはCライブラリ関数により適しています。たとえば、MSコンパイラは、標準のCスタイルルーチンの複数の「安全な」(strcpy_sなどの)バージョンを提供します。もちろん、これは他のプラットフォームでは利用できません。
  5. C++コードでCスタイルのルーチン(sprintfなど)を使用する場合は、十分に注意してください。 (私知っているそれは悪い習慣であると思われますが、いくつかのシナリオではこれは便利です)それらはわずかに異なる実装、拡張、および異なる数のパラメーターを持っています。たとえば、sprintfには、プラットフォームごとに異なる方法で実装される異なる追加の形式がある場合があります。たとえば、前回「%S」をチェックしたとき、vswprintfルーチンのmsvcとgccで動作が異なります。
  6. __int32などのコンパイラ固有のデータ型に依存しないでください。 4バイトの長さが保証されているある種の型(またはそのようなもの)が必要になる可能性が非常に高くなります。typedefを条件付きコンパイル( "#ifdef WIN32")と組み合わせて使用​​します。 ORクロスプラットフォームライブラリによって提供されるタイプを使用します。たとえば、SDLはUint8、Qt 4にはquint32などのタイプを提供します。これは、かなり一般的な方法です。
  7. 直接のOS呼び出しは避けてください。ファイルにアクセスするための標準機能を使用します。
  8. OS固有の呼び出しを使用する必要がある場合は、条件付きコンパイル(#ifdef WIN32など)を使用します。
  9. すべてのプラットフォームで同じビルドシステムを使用してみてください。 LinuxにはMSBuildはありません。 gnumake、cmake、scons、またはqmakeを使用します。これらのシステムの中には、異なるコンパイラのフラグをコーディングする必要があるものもありますが、どこでも同じスクリプトを使用することが可能です。たとえば、SConstructsとうまく連携します。また、すべてのプラットフォームで1つのビルドスクリプトを維持する方が、異なるビルドシステム間で変更を同期するよりも簡単な場合があります。
  10. オペレーティングシステムとの対話を必要とするすべての操作(G​​UI、ファイル操作)には、クロスプラットフォームライブラリを使用します。 Qtは良い選択です。
13
SigTerm

最初にコマンドラインプログラムを作成します。準備ができたら、 Qt などのクロスプラットフォームウィンドウツールキットを見つけます。

多言語コードの記述に興味がある場合は、プラットフォーム固有のライブラリに依存するのではなく、 [〜#〜] icu [〜#〜] などのサードパーティのUnicodeライブラリを使用してください。

5
robinjam

可能な場合はSTLタイプを使用してください。システム依存型とAPIの使用には注意してください。たとえば、WindowsではUINTやDWORDなどのタイプを使用しないでください。

Boostのようなライブラリを使用すると、移植可能なコードを簡単に作成できます。 GUIが必要な場合は、Qtのようなクロスプラットフォームツールキットの使用を検討してください。

プラットフォーム固有のコードを作成する必要がある場合があります。その場合は、次のようなことができます。

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
4
Brian R. Bondy

いくつかのガイドライン:

  1. コードのビジネスエンドとGUIを分離してください。
  2. コンパイラ固有の松葉杖(#pragmaなど)の使用は避けてください
  3. かわいいビット操作のトリックの代わりに、コンパイラ/プラットフォームで動作を変更しない従来の式を使用します。
  4. ハードウェアに触れると、デバイスドライバーに属します。
  5. Types.h(uint32_tなど)のようなデータ型ヘッダーを使用します。
  6. オペレーティングシステムコールを直接呼び出さないように、オペレーティングシステム抽象化レイヤーを使用します。

移植性を得るために、効率とパフォーマンスをトレードオフしなければならない場合があります。たとえば、コードでバッファー外のフィールドにアクセスする必要がある場合は、いつでもパック構造体をバッファーポインターにキャストできます。しかし、それはひどく移植性がありません。したがって、代わりに、オフセットで計算された名前付きポインターを使用する必要があります。境界調整処理コードを使用する場合もあります。きれいではありませんが、ポータブルです。幸いなことに、クラスインターフェイスを慎重に使用することで、そのようなものの多くを隠すことができます。

すべてのコードをそのように記述する必要はありません。明確に定義された責任の境界を使用して非常にモジュール化された方法でアプリケーションを設計する場合、コードの90〜95%を問題なく移植できます。次に、新しいプラットフォーム用にカスタマイズする必要がある非常にローカライズされた領域で5〜10%を分離します。

2
Amardeep AC9MF

不注意なプログラマーは、分類を試みることができる多くの罠に陥る可能性があります。しかし、最初にあなたに言わせてください:絶対としてそれは不可能です。

問題は、特定のコンパイラの問題のために、標準に準拠したコードでさえ移植できない可能性があることです。

これが私の頭の中で考えることができる主なカテゴリーです。

コンパイラ拡張

たとえば、変数配列の使用のように:

void func(int const n)
{
  int array[n];
}

これは標準ではありませんが、実用的であるため、多くのコンパイラがサポートしています。

標準ライブラリ拡張

多くの標準ライブラリの実装は、指定されたことのないstd::hash_mapを提供します。コードで使用する場合、移植性はありません。

現代の傾向は、このようなものをstd::tr1名前空間に隠して、プログラマーがこれが拡張機能であることを認識できるようにすることです。

また、多くの場合、typedefまたは汎用ではないマクロ(たとえば、PRETTY_FUNCTION)を定義していることに注意してください。標準ではマクロは指定されておらず、typedefはほとんど指定されていません。

プラットフォーム固有

たとえば、intまたはdoubleのサイズと配置は標準で指定されていません。ビットをいじって32ビットになると予想する場合は、コンパイラを変更しなくても64ビットプラットフォームに夢中になります。

プラットフォームAPI

私たちのプログラムはコンパイルすることを目的としており、多くの場合、プログラムが実行されているコンピューターと対話することを目的としています。

  • ハードウェアへのアクセス用
  • ファイルシステムへのアクセス用
  • 画面にアクセスするため

クロスプラットフォームのポータブルAPIを見つけるか、独自のAPIを作成する必要があります。以下のリストでいくつかのライブラリを確認してください。

ライブラリ

よく書かれたライブラリのほとんどは移植性が高いので、以下をサポートしていることを確認してください。

  • 興味のあるコンパイラ
  • 興味のあるプラットフォーム

優れたライブラリには次のものが含まれます。

  • Apache(ライブラリのコレクション)
  • ブースト
  • Qt(グラフィック用)
  • ICU(Unicode処理用)

あなたがレビューする必要がある他のもの...そしてそれは時間がかかります。

そこに完璧な答えはないと思います。ただし、完全な移植性はあり得ないため、サポートするコンパイラとプラットフォームを決定する必要があります。

プラットフォームの場合、Windowsと1つのLinuxフレーバーから始める必要があります。コンパイラーの場合は、任意の2つを選択します(余裕があればComeauを使用)。

2
Matthieu M.

他の人は前にそれを言いました、しかしここにそれについての私の見解があります:

1)C++が必要ですか?ベアメタルに近いため、ポータブルコードを作成するのに最適な言語ではありません。 Java、Python、Perl、PHPまたはJavascriptの方が適している場合があります。

2)C++が必要な場合は、完全に移植可能なコードを書き込もうとしないでください。とにかくほとんど不可能です。代わりに、サポートするプラットフォームを早期に決定してください。例:Linux、MacOS X、Windows

3)選択したすべてのプラットフォームでコードを継続的にテストするようにしてください。 Windowsでビルドするだけでなく、「完了したら」Linuxバージョンをコンパイルすることを期待してください。すべてのプラットフォームで毎日コンパイルし、問題がないかテストを続けてください。

2
Stijn de Witt

可能であれば、少なくとも2つの異なるコンパイラを使用してすべてのコードをコンパイルします。

1
Ben

学習のために、1つの実装に集中する本を避けるようにしてください。場合によっては、導入部または初期の章で、言語実装を取得または使用する方法について説明します。複数の実装について言及している場合は、おそらく問題ありません。

プラットフォームに依存しない参考書を入手してください。 StroustrupのC++プログラミング言語は優れたリファレンスですが、初心者が学ぼうとするのに適した本ではありません。特定の実装の参照に依存しないでください。たとえば、MSDNは便利ですが、主な焦点はVisual C++を使用してWindowsプログラムを作成する方法であり、どこでもコンパイルして実行するプログラムを作成する方法ではありません。

本当に便利なものを書くには、移植性のないコードに取り掛かる必要があります。互換性が最も低くなるのは、ユーザーインターフェイスコードを他のすべてのものから分離する習慣を身に付けるようにしてください。プラットフォーム間で変更する必要のあるコードが少ないほど、コードの移植性が高くなります。

1
David Thornley

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()関数を作成することさえできません。

1
Philipp

pOSIXシステムコールを使用することをお勧めします。そうすれば、スレッドを作成したり、ミューテックスやシグナルを使用したりするさまざまな方法に対処する必要がありません。

問題は、WindowsがPOSIXに完全に準拠していないことですが、次のような特定のPOSIX機能を実装するライブラリがあります。[1]: http://sourceware.org/pthreads-win32/

0
proind