問題タブ [abi]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - ポインターを渡すのではなく、C で構造体を値で渡すことの欠点はありますか?
ポインターを渡すのではなく、C で構造体を値で渡すことの欠点はありますか?
構造体が大きい場合、大量のデータをコピーするというパフォーマンス上の側面があることは明らかですが、構造体が小さい場合は、関数にいくつかの値を渡すのと基本的に同じにする必要があります。
戻り値として使用すると、さらに興味深いものになるかもしれません。C では、関数からの戻り値は 1 つしかありませんが、多くの場合、複数の値が必要になります。したがって、簡単な解決策は、それらを構造体に入れて返すことです。
これに賛成または反対の理由はありますか?
ここで私が話していることは誰にも明らかではないかもしれないので、簡単な例を挙げます。
C でプログラミングしている場合、遅かれ早かれ次のような関数を書き始めるでしょう。
これは問題ではありません。唯一の問題は、すべての関数で同じ規則を使用するために、パラメーターの順序について同僚と同意する必要があることです。
しかし、同じ種類の情報を返したい場合はどうなるでしょうか? 通常、次のようなものが得られます。
これは問題なく機能しますが、はるかに問題があります。戻り値は戻り値ですが、この実装ではそうではありません。上記から、関数 get_data が len が指すものを見ることが許可されていないことを伝える方法はありません。また、値が実際にそのポインターを介して返されることをコンパイラーにチェックさせるものは何もありません。そのため、来月、他の誰かがコードを正しく理解せずに (ドキュメントを読んでいなかったために) コードを変更すると、気付かないうちにコードが壊れたり、ランダムにクラッシュしたりします。
だから、私が提案する解決策は単純な構造体です
例は次のように書き直すことができます。
なんらかの理由で、ほとんどの人は本能的に inspect_data に構造体 blob へのポインターを持たせると思いますが、その理由はわかりません。ポインターと整数は引き続き取得されますが、それらが一緒になることははるかに明確です。get_data の場合、長さの入力値がなく、長さが返される必要があるため、前に説明した方法で混乱することはありません。
macos - Mac ABI が x86-32 に対して 16 バイトのスタック アラインメントを必要とするのはなぜですか?
古い PPC RISC システムや x86-64 の場合でも、この要件は理解できますが、実証済みの古い x86 の場合は? この場合、スタックは 4 バイト境界のみで整列する必要があります。はい、一部の MMX/SSE 命令では 16 バイトのアラインメントが必要ですが、それが呼び出し先の要件である場合は、アラインメントが正しいことを確認する必要があります。この追加の要件をすべての発信者に負担させるのはなぜですか? すべての呼び出しサイトがこの要件を管理する必要があるため、実際にはパフォーマンスが低下する可能性があります。何か不足していますか?
更新:これについてさらに調査し、社内の同僚と相談した結果、私はこれについていくつかの仮説を立てました。
- OS の PPC、x86、および x64 バージョン間の一貫性
- GCC codegen は、単純に「プッシュ」命令を実行するのではなく、sub esp,xxx を一貫して実行し、データをスタックに「移動」するようになりました。これは、一部のハードウェアでは実際に高速になる可能性があります。
- これは呼び出しサイトを少し複雑にしますが、呼び出し元がスタックをクリーンアップするデフォルトの "cdecl" 規則を使用する場合、余分なオーバーヘッドはほとんどありません。
最後の項目で私が抱えている問題は、呼び出し先がスタックをクリーニングすることに依存する呼び出し規則の場合、上記の要件がコード生成を実際に「醜く」することです。たとえば、一部のコンパイラが内部使用 (つまり、他の言語やソースからの呼び出しを意図していないコード) のために、より高速なレジスタ ベースの呼び出しスタイルを実装することを決定したものは何ですか? このスタックアライメントの問題は、いくつかのパラメーターをレジスターに渡すことによって達成されるパフォーマンスの向上の一部を無効にする可能性があります。
更新:これまでのところ、唯一の本当の答えは一貫性でしたが、私にはそれは少し簡単すぎる答えです。私は x86 アーキテクチャに関して 20 年以上の経験がありますが、パフォーマンスやその他の具体的なものではなく、一貫性が本当に理由である場合、開発者がそれを必要とするのは少しナイーブであることを丁重に提案します。彼らは、30 年近くにわたるツールとサポートを無視しています。特に、ツール ベンダーがツールを自社のプラットフォームにすばやく簡単に適応させることを期待している場合 (おそらくそうではないかもしれません... それはApple です...)
このトピックは別の日かそこらにあげて、閉じます...
関連している
assembly - 最新のシステムにおけるスタックの成長の方向性は?
C でいくつかのトレーニング資料を準備しており、サンプルを典型的なスタック モデルに適合させたいと考えています。
Linux、Windows、Mac OSX (PPC および x86)、Solaris、および最新の Unix では、C スタックはどの方向に成長しますか?
linux - Linux カーネルのアップグレード後に、VMware カーネル モジュールを再コンパイルする必要があるのはなぜですか?
Linux カーネルのアップグレード後、vmware-config.pl を使用して再構成作業 (カーネル モジュールのビルドを含む) を行うまで、VMWare サーバーを起動できません。
Windows VMWare ホストを最新の Windows Service Pack で更新すると、通常、VMWare を実行するために何もする必要はありません。
Linux と Windows で VMWare の動作が異なるのはなぜですか? この再コンパイル アクションは、Windows よりも Linux プラットフォームに利点をもたらしますか?
c++ - Boost を使用した下位互換性のある ABI を持つライブラリの作成
特定の C++ ライブラリ (またはそれ以上のフレームワーク) に取り組んでいます。API の互換性だけでなく ABI も維持しながら、以前のバージョンとの下位互換性を持たせたいと考えています (Qt の素晴らしい仕事のように)。
私は Boost の多くの機能を使用していますが、ユーザーにまったく同じ (場合によっては古い) バージョンの Boost を強制的に使用させない限り、下位互換性が不可能になっているように思えます。
Boostのユーザーバージョンとの干渉を防ぐために、名前空間の周りに「プレフィックス」を作成/名前を変更する方法はありますか(Boostの1/2を書き換えずに)?
たとえば、私の libXYZ は Boost 1.33 を使用しており、 class がありboost::foo
ます。バージョン 1.35 ではバージョンboost::foo
アップと新しいメンバーの追加が行われたため、boost::foo
1.33 および 1.35 からは ABI に対応していません。そのため、libXYZ のユーザーは Boost 1.33 を使用するか、Boost 1.35 で libXYZ を再コンパイルする必要があります (XYZ がコンパイルしない方法で API が壊れている可能性があります)。
注:動的リンクが静的リンクに似ている ELF を使用する UNIX/Linux OS について話しているため、シンボルが干渉するため、2 つの異なるバージョンのライブラリとリンクすることはできません。
私が考える適切な解決策の 1 つは、Boost を他のプライベート名前空間に配置することです。そのため、libXYZ は::XYZ::boost::foo
の代わりに使用し::boost::foo
ます。これにより、ユーザーが使用する可能性のある他のバージョンの Boost との衝突を防ぐことができます。
そのため、libXYZ は引き続き Boost 1.33 で動作し、静的または動的に他の名前空間にリンクされます。
- Boost API を外部に公開しません。
- 公開された API の安定したプライベート バージョンを保持します。
Boostでそのようなことを行う方法はありますか?
編集:最後に、ソース内のすべてのブースト シンボルの名前をカスタム シンボルに変更するスクリプトを作成することにしました。
根拠: コンパイラの可視性のサポートとは無関係に、ビルド プロセスを簡素化します。また、可視性は動的ライブラリでのみ機能し、静的では機能しないため、ライブラリの種類ごとに個別のビルドと依存関係が必要です。
スクリプトはhttp://art-blog.no-ip.info/files/rename.pyで入手できます。
編集 2: Boost BCP の最新バージョンは名前空間の名前変更をサポートしています。
windows - C ランタイム オブジェクト、dll 境界
Cランタイムに依存する「オブジェクト」(FILE *、mallocによって返されるポインターなど)を渡す問題を処理するDLL用のC APIを設計する最良の方法は何ですか. たとえば、2 つの dll が異なるバージョンのランタイムにリンクされている場合、ある dll から別の dll に FILE* を安全に渡すことはできないと理解しています。
Windows 依存の API (DLL 間で動作することが保証されている) を使用する唯一のソリューションはありますか? C API はすでに存在し、成熟していますが、ほとんどが UNIX の POV から設計されています (もちろん、UNIX でも動作する必要があります)。
c++ - DLL境界を越えてSTLリストを公開する方法は?
ホストアプリケーションのSTLコンテナに保存されているデータにアクセスする必要があるDLLがあります。C ++には標準のABIがなく、さまざまなコンパイラをサポートしたいので、アプリケーションとDLLの間のインターフェイスは、基本的にプレーンな古いデータのままにする必要があります。
ベクトルの場合、これは比較的簡単です。ベクトルのメモリブロックは連続していることが保証されているため、単純に返すことができます。
これで、DLLは、そのインターフェイスを介してベクターのデータに安全に読み取り専用でアクセスできるようになります。DLLはこれをラップして、コンテンツをそれ自体のベクターにコピーすることもできます。
STLリスト(および両端キュー)はどうですか?DLL境界を介したアクセスを許可する別の簡単な方法はありますか?それとも、ある種のGetFirst()/ GetNext()インターフェイスに頼る必要がありますか?多くのリストに対してこれを行う必要があるかもしれないので、ベクトルのような単純なソリューションがあると便利です。
performance - データ構造の調整がパフォーマンスにとって重要なのはなぜですか?
コンパイラがメンバーを整列させるためにデータ構造にパディングを追加する理由について、誰かが私に短くてもっともらしい説明を教えてもらえますか?CPUがより効率的にデータにアクセスできるようにするために行われていることは知っていますが、なぜそうなのかわかりません。
そして、これがCPUにのみ関連している場合、なぜLinuxではダブル4バイトが整列され、Windowsでは8バイトが整列されるのでしょうか。
linux - 共有ライブラリの ELF ヘッダーが Linux を OSABI として指定するのはなぜですか?
Linux システム (Fedora 9) の標準共有ライブラリはすべて、OSABI として ELFOSABI_NONE (0) を指定しています。
これは問題ありませんが、ELF ヘッダーで指定された OSABI が ELFOSABI_LINUX (3) である共有ライブラリをサプライヤから受け取りました。
これは、Linux システム用の共有ライブラリとしては不合理な値ではないように思えますが、私の他のすべてのライブラリとは異なる値です。私の他のライブラリの場合、これは「ELFファイルOS ABIが無効です」というエラーで失敗します。
FreeBSD ユーティリティbrandelf.cをコンパイルし、それを使用して OSABI タイプを 0 に変更したところ、ライブラリは他のすべてのもので正常に動作するようになりました。
私はただ疑問に思っています - なぜこのライブラリは ELFOSABI_LINUX としてマークされていると思いますか? おそらく、彼らは別のシステムでクロスコンパイルし、gcc フラグを指定して、この値を ELF ヘッダーに設定したのではないでしょうか? 同様のことを達成しようとしましたが、適切な gcc フラグを特定できませんでした。
この特定のサプライヤは多くの手を差し伸べないと何もしないので、考えられる原因を知りたいです。「あなたはおそらく X を行っていますが、これはあなたのライブラリを変更する必要があることを意味します。それらの配達を受け取った後」。
c++ - アプリケーションバイナリインターフェイスがプログラミングにとって重要なのはなぜですか
ABIがユーザースペースアプリケーションを開発する上で重要なコンテキストである理由がわかりません。オペレーティングシステムに対する一連のシステムコールはABIと見なされますか?しかし、もしそうなら、システムコールに関するすべての複雑さは標準ライブラリ内にカプセル化されていませんか?
では、システムコールはバイナリに埋め込まれるため、 ABIの互換性は、静的にリンクされたアプリケーションを異なるプラットフォームで実行する場合にのみ関係しますか?