C++/はじめに
開発環境を整える
編集Windowsの場合
編集Visual Stuido による方法
編集2021年現在、マイクロソフト社が開発・販売しているVisual Studio は、C/C++コンパイラを内包しており、配布条件に従えば無料で使えるバージョンもあります。 Visual Studio の利用にはアカウント登録(無料)が必要です。
GNU/Linuxのディストリビューションの場合
編集以下に、一般的なGNU/LinuxのディストリビューションへのC/C++開発環境のインストール方法を示します。主要なパッケージマネージャーごとに説明します。
- Debian/Ubuntu (apt パッケージマネージャー)
$ sudo apt update $ sudo apt install build-essential
- CentOS (dnf パッケージマネージャー)
$ sudo dnf install @development-tools
- Fedora (dnf パッケージマネージャー)
$ sudo dnf group install "C Development Tools and Libraries" "Development Tools"
- Arch Linux (Pacman パッケージマネージャー)
$ sudo pacman -S base-devel
- openSUSE (zypper パッケージマネージャー)
$ sudo zypper install -t pattern devel_basis
これらのコマンドを実行することで、各ディストリビューションでC/C++開発に必要なツールやライブラリがインストールされます。特定のパッケージマネージャーやディストリビューションのバージョンに応じて、インストール手順が異なる場合がありますので、ご注意ください。
- G++単体パッケージでなく開発環境のメタパッケージを使う理由
開発環境のメタパッケージ(例:build-essential
、@development-tools
など)を使用する理由はいくつかあります。
- 依存関係の自動解決: 開発環境のメタパッケージを使用すると、C/C++開発に必要な複数のツールやライブラリが一括してインストールされます。特に初心者の場合、必要なパッケージや依存関係を個別に把握することが難しい場合がありますが、メタパッケージを使用することでこれらの問題を回避できます。
- 開発環境の一貫性: メタパッケージを使用することで、開発環境の構築が一貫性を持って行われます。開発者やシステム管理者が同じメタパッケージを使用して開発環境をセットアップすることで、異なる環境間での互換性や共通の基盤を確保できます。
- 追加のツールやライブラリの提供: メタパッケージは、開発に役立つ追加のツールやライブラリも提供する場合があります。例えば、
build-essential
パッケージには、C/C++開発に必要な基本的なツールだけでなく、よく使用される追加のツールやライブラリも含まれています。 - 簡単なインストール: メタパッケージを使用すると、単一のコマンドで開発環境をセットアップできます。これにより、手動で複数のパッケージをインストールする手間が省けます。
したがって、開発環境のメタパッケージを使用することで、開発プロセスが簡素化され、一貫性が保たれ、開発に必要なツールやライブラリが効率的にインストールされる利点があります。
clang
編集GCC系のコンパイラ以外にも、clangというオープンソースのC言語系コンパイラがある。
なお、(GNU/Linuxではないが)FreeBSDやOpenBSDなどBSD系Unixでは、gcc のライセンス GPL を回避と性能面やコードのメンテナンスの容易さなどの理由で、clangが標準のC言語コンパイラとして採用されている。 マックで有名なアップル・コンピュータも、clangを援助している(macOSのユーザーランドは FreeBSD のフォーク)。
さて、その clang のインストールは、Fedora なら
sudo dnf install clang
でclang用の標準C言語コンパイラもC++コンパイラも一緒に入る。
C++のコンパイルのコマンドは
clang++ ファイル名.cc
である。
C++の用途
編集C++には、下記のような利点があります。
Windowsで標準的な言語として採用されている
編集一般的には、Windowsでアプリケーション開発をする際、Windowsが提供する統合開発環境 Visual Studio において基盤のプログラミング言語として採用している言語が、C++系のVisual C++ および C#系のVisual C# ですので、Windowsアプリを作成したい場合に、C++ の知識が必要になる可能性があります(C#はC++とは別の言語です。また標準C言語とのソース互換性は、C#にはありません。)。
なお余談ですが、Visual Studio は標準C言語のコンパイラを内包しており、C言語のソースを(C++のソースとしてではなく、ネイティブに)コンパイルすることが出来ます。例えば、ソースファイルの拡張子が(.ccではなく).c であれば標準C言語のコンパイラでコンパイルされ、sizeof(char) == sizeof(int) のような標準Cとしての挙動を示します[1]。
また、Linux kernel は記述言語にGCCを採用しています[2][3]。ただし、GNU/Linuxと称されるLinuxカーネルとGNUプロジェクトの成果物などのオープンソースのプログラムを組み合わせてOSの体をなした「ディストリビューション」のユーザーランドではC++で記述されたものもあります。例えば、GCC自身はC++で記述されています)。
CとC++の連携
編集C++は規格上、C++はCと一定のソース互換性を持っています。 そのため、C言語のコードは軽微な修正でC++で利用することができると期待できます。
プログラマがC言語で記述すると冗長で複雑なコードになる場合は、都合に応じてC++に切り替えることも可能です。ただし、両者の標準仕様に詳しくない場合、微細な意味論の違いからトラブルが生じる可能性があります。ミックスドランゲージプロジェクトにおいては、問題の解決にアセンブリ言語やリンケージの知識が必要な場面も珍しくありません。
- CとC++の標準ライブラリーをミックスして使ったC++のコード
#include <iostream> #include <cstdio> auto main() -> int { std::cout << "ようこそwelcome C++" << std::endl << std::flush; // C++のコード。ストリームバッファのフラッシュを忘れずに std::printf("こっちはC言語で出力\n"); // Cのコード }
- 実行結果
ようこそwelcome C++ こっちはC言語で出力
このC/C++の混在例の過去の編集では、
printf()
関数を使用しているにもかかわらず#include <cstdio>
を忘れていた- C++では
printf()
関数は名前空間 std に属している。 - C++のストリームへの出力の後に
std::printf()
を呼び出しているにもかかわらず、<< std::flush
を忘れていた。
などの不注意からくるバグが有り、このような不整合が環境によってはコンパイルエラーを引き起こす可能性があります。
このように、C++はCとの間に相互運用性がありますが、両方の言語の特性に精通している必要があります。
C++には class など、Cにない機能があり、そこは学習コストが高いのですが、しかしそういった高い学習コストを払ってでも、相互運用よりも低コストであると言えます。
CとC++の非互換性
編集CとC++は別々の言語であるため、根本的な意味論の違いに遭遇することがあります。
自動昇格の有無
編集C++では、char
は自動的にint
に昇格しません。
例えば、文字リテラルにsizeof
演算子を適用すると、C言語とC++で異なる結果が得られます。
- C言語のsizeof 'a'の値
#include <stdio.h> int main() { printf("sizeof 'a' ⇒ %zu\n", sizeof 'a'); }
- 実行結果
sizeof('a') => 4
- C言語では、char は int に自動昇格するのでintのバイト数(この場合は 4)が返ります。
- つぎに、同じソースコードを C++ でコンパイルして実行してみます。
- C++のsizeof 'a'の値
#include <stdio.h> int main() { printf("sizeof 'a' ⇒ %zu\n", sizeof 'a'); }
- 実行結果
sizeof('a') => 1
- 結果が異なりますね。
- これは、C言語はcharがintに自動昇格する仕様であるのに対し、C++では自動昇格されないためです。
この違いは、C++には関数オーバーロードの仕組みがあり
int func(int i); int func(char ch);
上記の2つの関数があったとき、両者は引数の違いによってのみ区別され、勝手に int に昇格される仕様では都合が悪いからです。
1文字をパラメーターとする関数のパラメーターを int で定義すると、Cなら有効ですがC++では未定義関数の呼出しとなります。
新しいキーワード
編集C++では、class
などが新しくキーワードとなり、変数名や関数名などの識別子に使用できなくなりました。
int class = 0; // C++ ではエラー
ポインタの代入の厳密さ
編集Cではポインタをvoid*
に変換することができますが、C++では明示的な変換が必要です。
void* ptr = NULL; int* iptr = ptr; // C++ ではエラー
初期化を含む宣言の飛越し
編集C++では、goto
やswitch
においても初期化を無視することはできません。
以下は、C言語では有効ですが、C++では無効です。
goto label; int skip = 1; // C++では初期化される label:
再宣言の禁止
編集C++では、再宣言は許されません。
struct X { int i; struct X *next; }; static struct X a; static struct X b = { 0, &a }; static struct X a = { 1, &b };
- このコードはCでは有効ですが、C++では
a
が再宣言となりエラーとなります。
struct スコープ
編集C++では、struct
もスコープを持ちます(struct
はclass
と同じくクラスです)。
Cでは、struct
はスコープを持ちません。
この様に、CとC++とには有意な差異があるのでCをバックグランドとするプログラマーが、C++に転向するときには新機能以外にも差異を学ぶ転換教育が必要です。
脚註
編集- ^ /std (言語の標準バージョンの指定) §C 標準のサポート
- ^ 基本的に標準C言語ですが、一部に asm goto などのGNU拡張を使用しています
- ^ GCCに対して高い互換性をもつClang/LLVMでも9.0.0からLinuxカーネルをコンパイルできます。