web-dev-qa-db-ja.com

言語はどのように拡大しますか?

私はC++を学んでいますが、GUIプログラムをコーディングする Qt の機能のいくつかについて学び始めたところです。私は次の質問を自問しました。

以前にOSにウィンドウやネットワーク経由で通信する方法を要求する構文がなかったC++(私も完全に理解していないAPIを使用して、私は認めています)が突然そのような機能を取得しますC++自体で記述されたライブラリを介して?それはすべて私にとってひどく循環的なようです。それらのライブラリでどのようなC++命令を思いつくことができますか?

この質問は、経験豊富なソフトウェア開発者にとっては些細なことのように思えるかもしれませんが、直接的な応答を見つけることなく何時間も研究しています。ライブラリの存在は私には理解できないので、Qtについてのチュートリアルに従うことができなくなるまでになりました。

208

コンピューターはタマネギのようなもので、純粋なハードウェアの内部コアから最も外側のアプリケーション層まで、多くの多く層があります。各層は自身の一部を次の外側の層に公開し、外側の層が内側の層の機能の一部を使用できるようにします。

例の場合Windowsオペレーティングシステムは、Windows上で実行されるアプリケーション用のいわゆるWIN32 APIを公開します。 QtライブラリはそのAPIを使用して、Qtを使用するアプリケーションを独自のAPIに提供します。 Qtを使用し、QtがWIN32を使用し、WIN32が下位レベルのWindowsオペレーティングシステムを使用し、ハードウェアで電気信号になるまで続きます。

195

あなたは、一般的に、ライブラリはまだ可能ではない何かを可能にすることはできないことは正しいです。

ただし、C++プログラムで使用できるようにするために、ライブラリをC++で作成する必要はありません。 C++で記述されていても、C++で記述されていない他のライブラリを内部で使用する場合があります。そのため、C++の外部でsomeを実行する方法がある限り、C++が実行する方法を提供しなかったという事実は、C++の追加を妨げません。

非常に低いレベルでは、C++(またはC)によって呼び出される一部の関数はAssemblyで記述され、Assemblyには、C++で不可能な(または簡単ではない)ことを行うために必要な命令が含まれています。システム関数。その時点で、そのシステムコールはanythingを実行できます。単にそれを止めるものがないからです。

60
user743382

CおよびC++には、OPが話しているこのすべての拡張性を可能にする2つのプロパティがあります。

  1. CおよびC++はメモリにアクセスできます
  2. CおよびC++は、CまたはC++言語以外の命令のアセンブリコードを呼び出すことができます。

カーネルまたは基本的な非保護モードプラットフォームでは、シリアルポートやディスクドライブなどの周辺機器は、RAM isと同じ方法でメモリマップにマッピングされます。メモリは一連のスイッチです周辺機器のスイッチ(シリアルポートやディスクドライバーなど)を切り替えると、周辺機器で便利なことができます。

プロテクトモードのオペレーティングシステムでは、ユーザー空間からカーネルにアクセスする場合(ファイルシステムへの書き込み時や画面上のピクセルの描画時など)、システムコールを行う必要があります。 Cにはシステムコールを行う命令がありませんが、Cは正しいシステムコールをトリガーできるアセンブラコードを呼び出すことができます。これにより、Cコードがカーネルと通信できるようになります。

特定のプラットフォームのプログラミングを簡単にするために、システムコールはより複雑な関数にラップされており、独自のプログラム内で有用な機能を実行できます。 1つは(アセンブラを使用して)システムコールを直接呼び出すことができますが、プラットフォームが提供するラッパー関数の1つを使用する方が簡単です。

システムコールよりもはるかに便利なAPIの別のレベルがあります。たとえば、mallocをご覧ください。これはシステムを呼び出して大きなメモリブロックを取得するだけでなく、行われていることをすべてのブックに記録することでこのメモリを管理します。

Win32 APIは、いくつかのグラフィック機能を共通のプラットフォームウィジェットセットでラップします。 Qtは、Win32(またはX Windows)APIをクロスプラットフォームの方法でラップすることにより、これをさらに進めています。

基本的に、CコンパイラはCコードをマシンコードに変換しますが、コンピューターはマシンコードを使用するように設計されているため、Cがライオンの共有またはコンピューターの機能を達成できることを期待する必要があります。ラッパーライブラリが行うことは、あなたが面倒な作業を行うだけなので、必要はありません。

43
doron

言語( C++ 11 など)は仕様であり、紙では、通常英語で書かれています。最新の C++ 11ドラフト をご覧ください(または、高価な 最終仕様 をISOベンダーから購入してください)。

通常、何らかの言語の実装を備えたコンピューターを使用します(原則として、コンピューターを使用せずにC++プログラムを実行できます。それは非倫理的で非効率的です)

一般的なC++実装は、一部のオペレーティングシステム上で動作し、それと通信します(一部の実装固有のコードを使用します(多くの場合、システムライブラリにあります)。通常、その通信は システムコール で行われます。 syscalls(2) を参照して、 Linuxカーネル で利用可能なシステムコールのリストを探してください。

アプリケーションの観点から見ると、syscallはx86-64上のSYSENTERのような基本的な機械語命令であり、いくつかの規則があります( [〜#〜] abi [〜#〜]

Linuxデスクトップでは、Qtライブラリは上記の X11 X11サーバーと通信するクライアントライブラリ Xorg スルー X Windowsプロトコル です。

Linuxでは、実行可能ファイルでlddを使用して、ライブラリの依存関係の(長い)リストを表示します。実行中のプロセスでpmapを使用して、実行時に「ロード」されるものを確認します。ところで、Linuxでは、アプリケーションはおそらくフリーソフトウェアのみを使用しているので、そのソースコード(QtからXlib、libc、...カーネルまで)を調べて、何が起きているかをさらに理解することができます。

23

あなたが不足している概念は システムコール だと思います。各オペレーティングシステムは膨大な量のリソースと機能を提供し、それらを利用して低レベルのオペレーティングシステム関連のことを実行できます。通常のライブラリ関数を呼び出す場合でも、おそらく舞台裏でシステムコールを行っています。

システムコールは、オペレーティングシステムのパワーを利用する低レベルの方法ですが、複雑で使いにくいため、APIに「ラップ」されているため、直接対処する必要はありません。しかし、その下では、O/S関連のリソースに関係するほぼすべての処理で、印刷、ネットワーク、ソケットなどのシステムコールが使用されます。

Windowsの場合、Microsoft WindowsのGUIは実際にカーネルに書き込まれているため、ウィンドウの作成、グラフィックの描画などのシステムコールがあります。他のオペレーティングシステムでは、GUIはカーネルの一部ではない場合があります。私が知る限り、GUIに関連するものに対するシステムコールはなく、低レベルのグラフィックスと入力関連のコールが利用可能である限り、より低いレベルでしか作業できませんでした。

19
Dave Cousineau

良い質問。すべての新しいCまたはC++開発者は、これを念頭に置いています。この記事の残りの部分では、標準のx86マシンを想定しています。 Microsoft C++コンパイラを使用している場合は、メモ帳を開いてこれを入力します(ファイルにTest.cという名前を付けます)

int main(int argc, char **argv)
{
   return 0
}

そして、このファイルをコンパイルします(開発者コマンドプロンプトを使用)cl Test.c /FaTest.asm

次に、メモ帳でTest.asmを開きます。表示されるのは翻訳されたコードです-C/C++はアセンブラーに翻訳されます。ヒントが得られますか?

_main   PROC
    Push    ebp
    mov ebp, esp
    xor eax, eax
    pop ebp
    ret 0
_main   ENDP

C/C++プログラムは、金属上で実行するように設計されています。つまり、低レベルのハードウェアにアクセスできるため、ハードウェアの機能を簡単に活用できます。たとえば、x86マシンでCライブラリgetch()を作成します。

アセンブラに応じて、次のように入力します。

_getch proc 
   xor AH, AH
   int 16h
   ;AL contains the keycode (AX is already there - so just return)
ret

アセンブラーで実行し、.OBJを生成します-getch.objという名前を付けます。

その後、Cプログラムを作成します(何も#includeしません)

extern char getch();

void main(int, char **)
{
  getch();
}

このファイルにGetChTest.cという名前を付けます。 getch.objを渡してこのファイルをコンパイルします。 (または、個別にコンパイルして.objとLINK GetChTest.Objとgetch.Objを一緒にコンパイルし、GetChTest.exeを生成します)。

GetChTest.exeを実行すると、キーボード入力を待機していることがわかります。

C/C++プログラミングは、言語だけではありません。優れたC/C++プログラマになるには、実行するマシンのタイプを十分に理解する必要があります。メモリ管理の処理方法、レジスタの構造などを知っておく必要があります。通常のプログラミングにはこれらの情報がすべて必要なわけではありませんが、非常に役立ちます。基本的なハードウェアの知識とは別に、コンパイラーの動作方法(つまり、変換方法)を理解しておけば、確実に役立ちます。これにより、必要に応じてコードを微調整できます。面白いパッケージです!

どちらの言語も__asmキーワードをサポートしているため、アセンブリ言語コードも混在させることができます。 CとC++を学習すると、全体的に優れた丸みのあるプログラマーになります。

アセンブラーと常にリンクする必要はありません。私はそれがあなたがよりよく理解するのを助けると思ったので、それを言及しました。ほとんどの場合、このようなライブラリ呼び出しのほとんどは、オペレーティングシステムが提供するシステムコール/ APIを利用します(OSはハードウェアとのやり取りを行います)。

15

C++は、C++自体で記述されたライブラリを介して、このような機能をどのように突然得るのでしょうか。

他のライブラリを使用することについて魔法のようなことは何もありません。ライブラリは、呼び出すことができる関数のシンプルで大きなバッグです。

このような関数を書くことを検討してください

_void addExclamation(std::string &str)
{
    str.Push_back('!');
}
_

そのファイルを含めると、addExclamation(myVeryOwnString);と書くことができます。ここで、「C++が突然感嘆符を文字列に追加する機能をどのように取得したのか」と尋ねるかもしれません。答えは簡単です。それを行う関数を作成してから呼び出しました。

C++で記述されたライブラリを介してウィンドウを描画する機能をC++がどのように取得できるかについての質問に答える場合、答えは同じです。他の誰かがそれを行うための関数を書き、それをコンパイルして、ライブラリの形であなたに渡しました。

他の質問は、ウィンドウ描画が実際にどのように機能するかを答えますが、ライブラリがどのように機能するかについて混乱しているように聞こえたので、質問の最も基本的な部分に対処したいと思いました。

10
Philip

重要なのは、オペレーティングシステムがAPIを公開する可能性と、このAPIの使用方法に関する詳細な説明です。

オペレーティングシステムは、呼び出し規則を備えた一連のAPIを提供します。呼び出し規約は、パラメーターがAPIに渡される方法、結果が返される方法、および実際の呼び出しを実行する方法を定義しています。

オペレーティングシステムとそれらのためのコードを作成するコンパイラーは一緒にうまく動作するので、通常、それについて考える必要はありません、ただそれを使用してください。

8
thst

まず、少し誤解されていると思います

C++は、以前はOSにウィンドウやネットワークを介した通信方法を要求できる構文がありませんでした。

OS操作を行うための構文はありません。 semanticsの問題です。

c ++自体で記述されたライブラリを介して突然そのような機能を取得する

さて、オペレーティングシステムはほとんどCで書かれています。共有ライブラリ(つまり、dll)を使用して外部コードを呼び出すことができます。さらに、オペレーティングシステムコードは、syscalls *またはinterruptsでシステムルーチンを登録できます。これらは、Assemblyを使用して呼び出すことができます。多くの場合、その共有ライブラリはシステム呼び出しを行うだけなので、インラインアセンブリを使用する必要はありません。

これに関する素晴らしいチュートリアルを次に示します。 http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
これはLinux向けですが、原則は同じです。

オペレーティングシステムは、グラフィックカード、ネットワークカードなどでどのように操作を行っていますか?非常に広範なテーマですが、ほとんどの場合、割り込み、ポートにアクセスするか、特定のメモリ領域にデータを書き込む必要があります。その操作は保護されているため、とにかくオペレーティングシステムを介して呼び出す必要があります。

7
Danubian Sailor

他の回答とは少し異なる見解を提供しようとして、このように回答します。

(免責事項:私は物事を少し単純化していますが、私が与える状況は純粋に仮説であり、人生に100%忠実であるというよりも概念を実証する手段として書かれています)。

別の観点から考えてみてください。基本的なスレッド化、ウィンドウ化、およびメモリ管理機能を備えたシンプルなオペレーティングシステムを作成したと想像してください。ユーザーがC++でプログラムできるようにC++ライブラリを実装し、ウィンドウの作成、ウィンドウへの描画などを実行する必要があります。問題は、これを行う方法です。

まず、C++はマシンコードにコンパイルされるため、マシンコードを使用してC++とインターフェイスする方法を定義する必要があります。これが関数の出番であり、関数は引数を受け取り、戻り値を与えるため、コードの異なるセクション間でデータを転送する標準的な方法を提供します。彼らはこれを、呼び出し規約として知られる何かを確立することによって行います。

呼び出し規約は、関数が実行されたときにそれらを見つけることができるように、引数をメモリ内のどこにどのように配置するかを示します。関数が呼び出されると、呼び出し元の関数は引数をメモリに配置してから、他の関数にジャンプするようにCPUに要求します。つまり、呼び出されるコードは絶対に何でもよく、関数の呼び出し方法は変更されません。ただし、この場合、関数の背後にあるコードはオペレーティングシステムに関連し、オペレーティングシステムの内部状態で動作します。

それで、数ヶ月後、すべてのOS機能が整理されました。ユーザーは関数を呼び出してウィンドウを作成し、その上に描画することができ、スレッドやあらゆる種類のすばらしいものを作成できます。問題はここにあります、あなたのOSの機能はLinuxの機能またはWindowsの機能と異なるでしょう。そのため、ユーザーが移植可能なコードを作成できるように、ユーザーに標準インターフェイスを提供する必要があると判断します。 QTの出番です。

ご存じのとおり、QTには、オペレーティングシステムが行う種類のことを実行するための便利なクラスと関数がたくさんありますが、基本的なオペレーティングシステムとは無関係に見えます。これが機能する方法は、QTがユーザーに表示される方法が統一されたクラスと関数を提供することですが、関数の背後にあるコードはオペレーティングシステムごとに異なります。たとえば、QTのQApplication :: closeAllWindows()は、使用されているバージョンに応じて、各オペレーティングシステムの特殊なウィンドウを閉じる関数を実際に呼び出します。 Windowsでは、おそらくCloseWindow(hwnd)を呼び出しますが、X Window Systemを使用するOSでは、XDestroyWindow(display、window)を呼び出す可能性があります。

明らかなように、オペレーティングシステムには多くの層があり、そのすべてが多くの種類のインターフェイスを介して相互作用する必要があります。私が触れていない多くの側面がありますが、それらを説明するにはすべて非常に長い時間がかかります。オペレーティングシステムの内部動作にさらに興味がある場合は、 OS dev wiki を確認することをお勧めします。

ただし、多くのオペレーティングシステムがインターフェイスをC/C++に公開することを選択する理由は、マシンコードにコンパイルすること、アセンブリ命令を独自のコードに混在させることができ、プログラマーに大きな自由度を提供することです。

繰り返しますが、ここでは多くのことが行われています。 .soや.dllファイルなどのライブラリをC/C++で記述する必要がなく、アセンブリや他の言語で記述できる方法を説明したいと思いますが、さらに追加する場合は、記事全体を書いて、それをやりたいと思っているのと同じくらい、私はそれをホストするサイトを持っていません。

7
Pharap

ウィンドウを作成するための特別な構文は必要ありません。必要なのは、OSがウィンドウを作成するためのAPIを提供することだけです。このようなAPIは、C++が構文を提供する単純な関数呼び出しで構成されています。

さらに、CおよびC++はいわゆるシステムプログラミング言語であり、任意のポインター(ハードウェアによっていくつかのデバイスにマップされる可能性があります)にアクセスできます。さらに、アセンブリで定義された関数を呼び出すことも非常に簡単です。これにより、プロセッサが提供するすべての操作を実行できます。したがって、CまたはC++と少量のアセンブリを使用してOS自体を記述することができます。

Qtは、いわゆるメタコンパイラを使用してextend C++ '構文を使用しているため、Qtが悪い例であることにも言及する必要があります。ただし、これは、OSが提供するAPIを呼び出して実際にウィンドウを描画または作成する機能とは関係ありません。

7
Joe

画面に何かを描画しようとすると、コードは他のコード(他のコードなど)を呼び出す他のコードを呼び出し、最終的にCPUが実行できる特別な命令である「システムコール」が発生します。これらの命令は、アセンブリで記述するか、コンパイラが「組み込み」(コンパイラがCPUが理解できる特別なコードに「特別に」処理する関数)をサポートする場合はC++で記述できます。彼らの仕事は、オペレーティングシステムに何かをするよう伝えることです。

システムコールが発生すると、最終的にディスプレイドライバーが画面に何かを描画するように指示されるまで、別の関数(など)を呼び出す関数が呼び出されます。その時点で、ディスプレイドライバーは物理メモリの特定の領域を調べます。これは実際にはnotメモリであり、むしろas ifそれはメモリでした。ただし、そのアドレス範囲に書き込むと、グラフィックスハードウェアがメモリ書き込みをインターセプトし、画面に何かを描画します。
このメモリ領域への書き込みは、ソフトウェア側では通常のメモリアクセスであるため、C++でcouldをコーディングすることです。ハードウェアが異なる方法で処理するだけです。
それは、それがどのように機能するかについての本当に基本的な説明です。

6
Mehrdad

C++プログラムはQtライブラリ(C++でコーディングされている)を使用しています。 QtライブラリはWindows CreateWindowEx 関数(kernel32.dll内のCでコーディングされた)を使用します。またはLinuxでは Xlib (Cでもコード化)を使用している可能性がありますが、Xプロトコルでは「」を意味する生のバイトを送信することもできます私のためのウィンドウ」。

catch-22の質問に関連するのは、実際には「最初のC++コンパイラはC++で書かれた」という歴史的なメモですそれは、いくつかのC++の概念を備えたCコンパイラであり、最初のバージョンをコンパイルして、それ自体をコンパイルするのに十分でした。

同様に、GCCコンパイラーはGCC拡張機能を使用します。最初にバージョンにコンパイルされ、次にそれ自体を再コンパイルするために使用されます。 (GCCビルド手順)

4
Ángel

質問の見方これは実際にはコンパイラーの質問です。

このように見て、Z ++を呼び出す新しい言語をアセンブリに変換するコードをAssemblyで記述します(任意の言語で実行できます)。 。

ここで、このコンパイラにいくつかの基本的な機能を与えて、int、string、arrayなどを記述できるようにします。実際には、コンパイラ自体をZ ++で記述できるように十分な機能を与えます。そして今、Z ++で書かれたZ ++のコンパイラがあります。

さらに素晴らしいのは、既存の機能を使用してコンパイラに機能を追加できるようになったことです。これにより、以前の機能を使用してZ ++言語を新しい機能で拡張できます。

たとえば、任意の色のピクセルを描画するのに十分なコードを記述する場合、Z ++を使用してそれを展開し、必要なものを描画できます。

2

これを可能にするのはハードウェアです。グラフィックスメモリは、大きな配列(画面上のすべてのピクセルで構成される)と考えることができます。画面に描画するには、C++またはそのメモリに直接アクセスできる任意の言語を使用して、このメモリに書き込むことができます。そのメモリは、グラフィックカードからアクセスできるか、グラフィックカード上にあるだけです。

最新のシステムでは、グラフィックメモリに直接アクセスするには、さまざまな制限があるため、間接的な手段を使用してドライバーを作成する必要があります。ウィンドウ(実際には他の画像のような単なる画像)を作成し、その画像をグラフィックメモリに書き込み、GPUが画面に表示するライブラリ。ポインターの目的である特定のメモリー位置に書き込む機能を除いて、言語に何も追加する必要はありません。

0
john