C言語、C++、C#は名前がよく似ていますが、設計思想、実行方式、メモリ管理、得意な開発分野が大きく異なるプログラミング言語です。
それぞれの特徴を簡単に表すと、次のようになります。
- C言語:ハードウェアに近い処理や組み込み開発に強い
- C++:高い実行性能と大規模開発を両立しやすい
- C#:安全性と開発効率を重視したアプリケーション開発に強い
どの言語が優れているかというよりも、開発するシステムや目的に応じて適切な言語が異なります。
C言語・C++・C#の比較表
| 項目 | C言語 | C++ | C# |
|---|---|---|---|
| 主な特徴 | 手続き型・構造化プログラミング中心 | マルチパラダイム | オブジェクト指向中心のマルチパラダイム |
| 主な実行方式 | ネイティブコード | ネイティブコード | .NETによるJITまたはAOT |
| 動的メモリ管理 | 主に手動 | RAIIやスマートポインタが中心 | ガベージコレクションが中心 |
| ポインタ | 頻繁に使用する | 使用可能 | 通常は使用しない |
| 実行性能 | 高い | 高い | 高いがランタイムやGCの影響を受ける場合がある |
| ハードウェア制御 | 得意 | 得意 | 一般的な用途では限定的 |
| 学習難易度 | 文法は比較的少ないが、メモリ管理が難しい | 言語仕様が広く難易度が高い | 比較的始めやすい |
| 主な用途 | OS、組み込み、マイコン、ドライバ | ゲーム、CAD、映像処理、金融、ロボット | Web、業務システム、Unity、クラウド |
| ガベージコレクション | 基本的になし | 基本的になし | あり |
| クロスプラットフォーム | 対応しやすい | 対応しやすい | .NET対応環境で利用可能 |
C言語とは
C言語は、1970年代に開発された汎用プログラミング言語です。
コンピューターのハードウェアに近い処理を記述しやすく、OS、マイコン、家電、自動車、産業機器などで広く利用されています。
C言語の主な特徴
C言語は、処理を関数に分けて順番に実行する手続き型プログラミングを中心とした言語です。
言語仕様は比較的コンパクトですが、メモリやポインタを直接扱う場面が多いため、実際に安全なプログラムを書くには十分な知識が必要です。
ハードウェアに近い処理を記述できる
C言語では、ポインタを使ってメモリアドレスを扱えます。
#include <stdio.h>
int main(void)
{
int number = 10;
int *pointer = &number;
printf("%d\n", *pointer);
return 0;
}
このコードでは、変数numberのメモリアドレスをpointerに格納し、そのアドレスを通じて値を取得しています。
ポインタを使うことで、効率的なデータ処理や、組み込み環境におけるハードウェア制御を実現できます。
ただし、一般的なOS上のアプリケーションが、自由にハードウェアへ直接アクセスできるわけではありません。
実際には、OSのAPI、デバイスドライバ、メモリマップドI/O、ベンダー提供のSDKなどを通して制御します。
動的メモリを手動で管理する
C言語では、mallocなどを使って動的に確保したメモリを、不要になった時点でfreeによって解放します。
#include <stdlib.h>
int main(void)
{
int *numbers = malloc(sizeof *numbers * 100);
if (numbers == NULL)
{
return 1;
}
free(numbers);
return 0;
}
freeを忘れると、不要になったメモリが解放されず、メモリリークにつながる可能性があります。
ただし、C言語のすべての変数を手動で解放するわけではありません。
関数内で宣言した通常のローカル変数は、そのスコープを抜けると寿命が終了します。
実行性能が高い
C言語のプログラムは、一般的に対象環境向けのネイティブコードへコンパイルされます。
メモリ配置やデータ構造を細かく制御できるため、処理性能やメモリ使用量が重視される分野に向いています。
ただし、C言語だから必ず高速になるわけではありません。
実際の性能は、アルゴリズム、実装方法、コンパイラの最適化、使用するライブラリなどによって変わります。
C言語のメリット
C言語には、次のようなメリットがあります。
- 実行性能が高い
- メモリ使用量を細かく制御できる
- 対応しているCPUやOSが多い
- 組み込み機器やマイコン開発に向いている
- コンピューターの仕組みを理解しやすい
- 多くの言語やシステムの基礎として使われている
C言語のデメリット
一方で、次のような注意点があります。
- 動的メモリを手動で管理する必要がある
- ポインタの扱いが難しい
- 配列の範囲外アクセスを検出しにくい
- バッファオーバーフローなどの脆弱性が生まれやすい
- 大規模開発ではコード管理が複雑になりやすい
- 標準機能だけでは高度なデータ構造を扱いにくい
C言語が使われる主な分野
C言語は、次のような分野で利用されています。
- OS
- デバイスドライバ
- マイコン
- 組み込みシステム
- 家電製品
- 自動車制御
- 産業機械
- 通信機器
- データベースエンジン
- プログラミング言語の処理系
C++とは
C++は、C言語を基礎として発展した汎用プログラミング言語です。
C言語に近い性能や低レベル制御を維持しながら、クラス、テンプレート、例外処理、標準ライブラリなど、大規模なソフトウェア開発に必要な機能を備えています。
現在のC++は、単にC言語へオブジェクト指向を追加しただけの言語ではありません。
独自の型システム、オブジェクトモデル、テンプレート、標準ライブラリを持つ、別個のプログラミング言語として考える必要があります。
C++の主な特徴
C++は、複数のプログラミング手法を組み合わせて利用できるマルチパラダイム言語です。
主に次のような書き方に対応しています。
- 手続き型プログラミング
- オブジェクト指向プログラミング
- ジェネリックプログラミング
- 関数型に近いプログラミング
- コンパイル時プログラミング
用途に応じて、高性能な低レベル処理と、保守性を重視した高レベルな設計を組み合わせられます。
オブジェクト指向を利用できる
C++では、データと処理をまとめたクラスを定義できます。
#include <iostream>
#include <string>
class User
{
private:
std::string name;
public:
explicit User(const std::string& userName)
: name(userName)
{
}
void greet() const
{
std::cout << "こんにちは、"
<< name
<< "さん"
<< std::endl;
}
};
int main()
{
User user("田中");
user.greet();
return 0;
}
この例では、名前のデータと挨拶を行う処理をUserクラスにまとめています。
クラスを使うことで、プログラム内の役割や責任を整理しやすくなります。
テンプレートを利用できる
C++には、型に依存しない汎用的な処理を書くためのテンプレートがあります。
template <typename T>
T add(T a, T b)
{
return a + b;
}
この関数は、整数や小数など、複数の型に対して利用できます。
int result1 = add(10, 20);
double result2 = add(1.5, 2.5);
テンプレートは、C++標準ライブラリのコンテナやアルゴリズムでも広く使われています。
標準ライブラリが充実している
C++標準ライブラリには、配列、文字列、動的配列、連想配列、アルゴリズム、スレッド、ファイルシステムなど、さまざまな機能が含まれています。
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> numbers = {5, 2, 8, 1, 3};
std::sort(numbers.begin(), numbers.end());
for (int number : numbers)
{
std::cout << number << std::endl;
}
return 0;
}
このコードでは、std::vectorで整数の一覧を管理し、std::sortで並べ替えています。
C言語で同等の処理を書くよりも、安全性や再利用性を高めやすくなります。
RAIIによってリソースを管理する
現代的なC++では、RAIIという考え方を使って、メモリ、ファイル、ロックなどのリソースを管理します。
RAIIでは、オブジェクトの寿命とリソースの寿命を結び付けます。
#include <memory>
int main()
{
auto number = std::make_unique<int>(10);
return 0;
}
numberがスコープを抜けると、所有しているメモリが解放されます。
C++では、必要に応じてnewとdeleteを直接使うこともできますが、現代的な開発では、次のような機能を利用するのが一般的です。
std::vectorstd::stringstd::unique_ptrstd::shared_ptrstd::arraystd::optional
ただし、スマートポインタを使えばすべてのメモリ問題が解決するわけではありません。
たとえば、std::shared_ptr同士が循環参照すると、参照カウントがゼロにならず、解放されないことがあります。
C++のメリット
C++には、次のようなメリットがあります。
- 実行性能が高い
- メモリやCPUの使用方法を細かく制御できる
- オブジェクト指向を利用できる
- テンプレートによる高い再利用性がある
- 高性能な大規模ソフトウェアを開発できる
- ゲーム、映像処理、数値計算などに強い
- RAIIによる決定的なリソース管理ができる
C++のデメリット
一方で、次のような難しさがあります。
- 言語仕様が非常に広い
- 学習する内容が多い
- ポインタやオブジェクトの寿命管理が難しい
- テンプレートのエラーメッセージが複雑になることがある
- ビルド環境や依存関係の管理が難しい場合がある
- 書き方によってコード品質に大きな差が出やすい
- 古い書き方と現代的な書き方が混在しやすい
C++が使われる主な分野
C++は、次のような分野で利用されています。
- ゲームエンジン
- 3Dゲーム
- CAD
- 映像編集ソフト
- Webブラウザ
- データベース
- 金融取引システム
- ロボット
- 自動運転
- AI推論エンジン
- OS
- 組み込みシステム
- 高性能なデスクトップアプリ
C#とは
C#は、Microsoftが中心となって開発した、.NET向けのプログラミング言語です。
オブジェクト指向を中心としながら、関数型プログラミングに近い機能や、非同期処理、パターンマッチングなども備えています。
C言語やC++と比べると、メモリ管理や開発環境が整備されており、Web、業務システム、クラウド、ゲームなどのアプリケーション開発を進めやすい言語です。
C#の主な特徴
C#は、通常.NETの実行環境を利用して動作します。
C#のソースコードは、多くの場合、まず中間言語へコンパイルされます。
その後、実行時にJITコンパイラが対象CPU向けのネイティブコードへ変換します。
C#のソースコード
↓
中間言語
↓
.NETランタイム
↓
ネイティブコードとして実行
現在の.NETでは、実行前にネイティブコードへ変換するAOTも利用できます。
そのため、C#は必ず実行時にのみコンパイルされるわけではありません。
ガベージコレクションがある
C#では、不要になったマネージドオブジェクトのメモリを、ガベージコレクターが自動的に回収します。
User user = new User("田中");
通常、C言語のfreeやC++のdeleteに相当する処理を、プログラマーが直接記述する必要はありません。
これにより、次のような問題を防ぎやすくなります。
- 二重解放
- 解放済みメモリへのアクセス
- 動的メモリの解放忘れ
- 一般的なダングリングポインタ
ただし、C#でもメモリリークが完全になくなるわけではありません。
不要なオブジェクトへの参照を保持し続けると、ガベージコレクターはそのオブジェクトを回収できません。
たとえば、次のような状況では注意が必要です。
- 静的コレクションへデータを追加し続ける
- イベントの購読解除を忘れる
- キャッシュを無制限に保持する
- タイマーがオブジェクトを参照し続ける
- 長時間動作するサービスで不要な参照が蓄積する
外部リソースは明示的に解放する
ガベージコレクションが管理するのは、主にマネージドメモリです。
ファイル、データベース接続、ネットワークソケットなどの外部リソースは、不要になった時点で適切に解放する必要があります。
C#では、通常usingを利用します。
using var stream = File.OpenRead("sample.txt");
usingのスコープを抜けると、Disposeが呼び出され、リソースが解放されます。
オブジェクト指向を中心に設計されている
C#では、クラス、構造体、インターフェースなどを使ってプログラムを設計します。
using System;
public class User
{
public string Name { get; }
public User(string name)
{
Name = name;
}
public void Greet()
{
Console.WriteLine($"こんにちは、{Name}さん");
}
}
public class Program
{
public static void Main()
{
var user = new User("田中");
user.Greet();
}
}
C++と似た文法もありますが、メモリ管理や標準ライブラリの利用方法は大きく異なります。
非同期処理を書きやすい
C#では、asyncとawaitを使って、非同期処理を比較的分かりやすく記述できます。
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
using var client = new HttpClient();
string result =
await client.GetStringAsync("https://example.com");
System.Console.WriteLine(result);
}
}
Web通信、ファイル操作、データベースアクセスなど、待ち時間が発生する処理で利用されます。
ただし、asyncとawaitを使ったからといって、必ず新しいスレッドが作成されるわけではありません。
非同期I/Oでは、処理の完了を待っている間、スレッドを長時間占有しないようにできます。
LINQを利用できる
C#では、LINQを使って、配列、リスト、データベースなどのデータを簡潔に操作できます。
using System;
using System.Linq;
public class Program
{
public static void Main()
{
int[] numbers = { 1, 2, 3, 4, 5, 6 };
var evenNumbers =
numbers.Where(number => number % 2 == 0);
foreach (int number in evenNumbers)
{
Console.WriteLine(number);
}
}
}
この例では、数値の一覧から偶数だけを抽出しています。
LINQの処理は、記述した時点ではなく、実際に列挙した時点で実行される場合があります。
開発環境が充実している
C#は、Visual StudioやVisual Studio Codeなどの開発環境との相性が良く、次のような機能を利用できます。
- 入力補完
- エラー検出
- デバッグ
- リファクタリング
- テスト
- パッケージ管理
- プロジェクト管理
このため、個人開発だけでなく、企業のチーム開発でも利用しやすい言語です。
C#のメリット
C#には、次のようなメリットがあります。
- ガベージコレクションによる自動メモリ管理
- CやC++と比べてアプリ開発を始めやすい
- 標準ライブラリが充実している
- 開発ツールが充実している
- WebアプリやWeb APIを開発できる
- Unityによるゲーム開発ができる
- 非同期処理を書きやすい
- Windows、Linux、macOSで利用できる
- 型安全性が比較的高い
C#のデメリット
一方で、次のような注意点があります。
- CやC++ほど細かなメモリ制御には向かない
- ガベージコレクションによる処理時間の変動がある
- 厳密なハードリアルタイム処理には慎重な設計が必要
- 通常は.NETランタイムを利用する
- アンマネージドコードとの連携には追加知識が必要
- 高度な非同期処理やGC最適化は難しい
なお、自己完結型の配布やNative AOTを利用すれば、利用者が.NETランタイムを別途インストールしなくても実行できる構成にできます。
C#が使われる主な分野
C#は、次のような分野で利用されています。
- 業務システム
- Webアプリケーション
- Web API
- Windowsアプリ
- クラウドサービス
- Unityによるゲーム開発
- 社内ツール
- バッチ処理
- デスクトップアプリ
- モバイルアプリ
メモリ管理の違い
C言語、C++、C#の大きな違いの一つが、メモリとリソースの管理方法です。
C言語のメモリ管理
C言語では、mallocやcallocで動的に確保したメモリを、freeで解放します。
int *data = malloc(sizeof *data * 100);
if (data != NULL)
{
free(data);
}
自由度は高い一方で、次のような問題が起こる可能性があります。
- メモリリーク
- 二重解放
- 解放済みメモリへのアクセス
- NULLポインタ参照
- 配列の範囲外アクセス
C++のリソース管理
C++では、RAII、標準コンテナ、スマートポインタを使ってリソースを管理します。
auto data = std::make_unique<int[]>(100);
このメモリは、dataの寿命が終了すると解放されます。
C#のガベージコレクションとは異なり、C++ではスコープを抜けた時点など、オブジェクトの寿命に応じて決定的にデストラクタが呼ばれます。
C#のメモリ管理
C#では、ガベージコレクターが、到達不能になったマネージドオブジェクトを回収します。
int[] data = new int[100];
通常、プログラマーがメモリ解放を直接行う必要はありません。
ただし、回収されるタイミングはガベージコレクターが判断するため、必ずしも不要になった瞬間に解放されるわけではありません。
実行方式の違い
C言語、C++、C#では、ソースコードからプログラムが実行されるまでの流れも異なります。
C言語とC++の実行方式
C言語とC++は、一般的に対象OSやCPU向けのネイティブコードへコンパイルされます。
ソースコード
↓
コンパイル
↓
リンク
↓
実行ファイル
↓
OSがメモリへ読み込む
↓
CPUが機械語を実行
Windows向けに作成した実行ファイルを、そのままLinuxやmacOSで実行できるとは限りません。
基本的には、対象環境ごとにコンパイルする必要があります。
C#の実行方式
C#では、一般的に中間言語へコンパイルした後、.NETがネイティブコードへ変換します。
C#ソースコード
↓
中間言語
↓
JITまたはAOT
↓
ネイティブコード
↓
実行
JITでは、プログラムの実行時にネイティブコードへ変換します。
AOTでは、実行前にネイティブコードへ変換します。
プログラミングスタイルの違い
3つの言語では、プログラムの組み立て方にも違いがあります。
C言語は手続き型が中心
C言語では、処理を関数に分け、順番に実行していく構成が基本です。
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main(void)
{
int result = add(10, 20);
printf("%d\n", result);
return 0;
}
小規模なプログラムでは分かりやすい一方、規模が大きくなると、データと処理の関係を整理する工夫が必要です。
C++は複数の書き方を利用できる
C++では、C言語に近い手続き型の書き方も、クラスを使ったオブジェクト指向の書き方もできます。
さらに、テンプレートやラムダ式などを使った設計も可能です。
性能が重要な部分は低レベルに記述し、アプリケーション全体はクラスや抽象化を使って整理するなど、柔軟な設計ができます。
C#はオブジェクト指向を中心に設計する
C#では、クラス、構造体、インターフェースなどを利用してプログラムを構成します。
一方で、現在のC#には、トップレベルステートメント、ラムダ式、LINQ、レコード型、パターンマッチングなどもあります。
そのため、C#はオブジェクト指向だけに限定された言語ではありません。
ポインタの違い
ポインタの扱いも、3言語で大きく異なります。
C言語ではポインタが中心的な機能
C言語では、配列、文字列、動的メモリ、構造体、関数への引数など、多くの場面でポインタを使用します。
ポインタを理解しないまま、実践的なCプログラムを書くことは難しいといえます。
C++では生ポインタとスマートポインタを使い分ける
C++でも生のポインタを使用できます。
ただし、所有権を表す場合には、次のようなスマートポインタを利用するのが一般的です。
std::unique_ptrstd::shared_ptrstd::weak_ptr
生ポインタは必ずしも悪いものではありません。
所有権を持たない参照や、既存オブジェクトを一時的に指す用途などでは、生ポインタが使われる場合もあります。
C#では通常ポインタを使わない
一般的なC#開発では、ポインタを意識する場面はほとんどありません。
必要であればunsafeを使ってポインタを扱えますが、Webアプリや業務システムでは通常使用しません。
また、C#には、ポインタを直接使わずに高性能なメモリ操作を行うための機能もあります。
Span<T>ReadOnlySpan<T>Memory<T>refstackalloc
オブジェクト指向の違い
C言語、C++、C#では、オブジェクト指向機能の有無や設計方法も異なります。
C言語にはクラスがない
C言語には、言語機能としてクラス、継承、仮想関数などがありません。
ただし、構造体と関数ポインタを組み合わせて、オブジェクト指向に近い設計を実現することはできます。
typedef struct
{
int x;
int y;
} Point;
void move(Point *point, int dx, int dy)
{
point->x += dx;
point->y += dy;
}
C++は多彩なオブジェクト指向機能を持つ
C++では、次のような機能を利用できます。
- クラス
- 継承
- 多態性
- 仮想関数
- カプセル化
- 演算子オーバーロード
- 多重継承
非常に柔軟ですが、複雑な継承構造は、保守性を下げる原因になることもあります。
C#は単一継承とインターフェースを利用する
C#でも、クラス、継承、多態性、インターフェースを利用できます。
ただし、クラスの多重継承には対応していません。
1つの基底クラスを継承し、必要に応じて複数のインターフェースを実装します。
public class Sample :
BaseClass,
IDisposable,
IComparable
{
}
C++より制約がある分、継承関係が複雑になりにくい傾向があります。
エラーや不具合の起こりやすさ
それぞれの言語には、起こりやすい問題があります。
C言語で起こりやすい問題
C言語では、次のような問題に注意が必要です。
- NULLポインタ参照
- 配列の範囲外アクセス
- メモリリーク
- 二重解放
- 解放済みメモリへのアクセス
- バッファオーバーフロー
- 初期化していない変数の使用
これらの問題は、プログラムの異常終了だけでなく、セキュリティ上の脆弱性につながる場合があります。
C++で起こりやすい問題
C++では、C言語と共通する問題に加えて、次のような問題があります。
- オブジェクトの寿命管理
- コピーとムーブの誤り
- 継承関係の設計ミス
- 例外安全性の不足
- 所有権の不明確さ
- テンプレートによる複雑なエラー
shared_ptrの循環参照
現代的なC++の設計手法を使うことで、多くの問題を減らせます。
C#で起こりやすい問題
C#では、CやC++のような不正なメモリアクセスは起こりにくい一方、次のような問題があります。
null参照- 非同期処理の誤り
- デッドロック
- リソースの解放漏れ
- イベント購読によるメモリ保持
- キャッシュの肥大化
- ガベージコレクションによる性能変動
C#は比較的安全性の高い言語ですが、不具合が起こらないわけではありません。
実行性能の違い
C言語、C++、C#の性能を、単純に順位付けすることはできません。
実際の速度は、次の要素によって変わります。
- アルゴリズム
- データ構造
- コンパイラ
- 最適化設定
- メモリアクセス
- ライブラリ
- CPU
- OS
- ネットワークやストレージの待ち時間
- ガベージコレクション
C言語が有利になりやすい場面
C言語は、次のような場面で有利です。
- メモリ容量が非常に少ない
- CPU性能が限られている
- マイコンを制御する
- 実行ファイルを小さくしたい
- OSやドライバを開発する
- ハードウェアに近い処理が必要
C++が有利になりやすい場面
C++は、次のような場面に向いています。
- 高速処理と大規模設計を両立したい
- 3Dグラフィックスを扱う
- ゲームエンジンを開発する
- 低遅延処理が必要
- リアルタイム性が求められる
- 高性能なデスクトップアプリを作る
C#が有利になりやすい場面
C#は、次のような場面に向いています。
- 開発速度を重視する
- 業務システムを作る
- Web APIを開発する
- チーム開発を行う
- 保守性を重視する
- Unityでゲームを作る
- クラウドサービスを開発する
C#もJITやAOTによって高い性能を発揮します。
ただし、ガベージコレクションの影響や、メモリ配置を細かく制御しにくい点では、CやC++と異なります。
ゲーム開発における違い
ゲーム開発でも、C++とC#は異なる役割で使われます。
C++は高性能なゲームやゲームエンジンに向いている
C++は、次のような処理に向いています。
- 描画エンジン
- 物理演算
- AI処理
- メモリ最適化
- 大規模な3D空間
- 高いフレームレートが必要なゲーム
Unreal Engineでは、C++とBlueprintを組み合わせて開発できます。
エンジン内部、高性能な処理、複雑なゲームシステムにはC++が利用されます。
C#はUnityによるゲーム開発に向いている
Unityでは、主にC#を使って次のような処理を記述します。
- キャラクター操作
- ゲームルール
- UI
- アイテム管理
- イベント処理
- エディタ拡張
C++と比べてメモリ管理を意識する場面が少なく、ゲームの仕組みやコンテンツ制作に集中しやすい点が特徴です。
ただし、Unityのエンジン内部がすべてC#で実装されているわけではありません。
C言語は低レベル部分で使われることがある
現在の大規模なゲームをC言語だけで開発するケースは多くありません。
一方で、次のような部分ではC言語が使われる場合があります。
- 低レベルライブラリ
- ゲーム機向けシステム
- 組み込み機器
- 古いゲーム
- C形式のAPI
Web開発における違い
Web開発では、C#が一般的なWebアプリケーション開発に向いています。
CやC++は、Webを支える基盤ソフトで使われることがあります。
C言語はWebの基盤で使われる
C言語は、一般的なWebサイトや管理画面を直接開発する用途では、あまり選ばれません。
一方で、次のような基盤ソフトでは重要な役割を持っています。
- Webサーバー
- データベース
- OS
- 暗号ライブラリ
- 通信ライブラリ
- 言語ランタイム
C++は高性能なサーバーや基盤処理に使われる
C++でも、Webサーバー、API、通信処理、バックエンド基盤を開発できます。
ただし、一般的な業務Webシステムでは、開発効率や保守性を重視して、C#、Java、TypeScript、Python、PHP、Goなどが選ばれることが多くあります。
C#はASP.NET CoreによるWeb開発に向いている
C#では、ASP.NET Coreを使って次のようなシステムを開発できます。
- Webサイト
- Web API
- ECサイト
- 会員システム
- 管理画面
- 社内システム
- クラウドサービス
- マイクロサービス
Microsoft Azureとの連携にも強く、企業向けシステムで広く利用されています。
文法の違い
同じHello Worldを表示するコードでも、書き方が異なります。
C言語のHello World
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
C++のHello World
#include <iostream>
int main()
{
std::cout
<< "Hello, World!"
<< std::endl;
return 0;
}
C#のHello World
Console.WriteLine("Hello, World!");
現在のC#では、トップレベルステートメントを利用できるため、ProgramクラスやMainメソッドを明示せずに記述できます。
ただし、内部的にはエントリーポイントに相当する処理が生成されています。
配列の違い
配列の安全性にも違いがあります。
C言語の配列
int numbers[3] = {10, 20, 30};
printf("%d\n", numbers[0]);
C言語では、配列の範囲外へアクセスしても、必ずエラーになるとは限りません。
printf("%d\n", numbers[100]);
このようなコードは未定義動作です。
異常終了する場合もあれば、偶然何らかの値が表示されたり、別のメモリを破壊したりする場合もあります。
C++の配列
C++では、std::vectorを利用できます。
#include <iostream>
#include <vector>
int main()
{
std::vector<int> numbers = {10, 20, 30};
std::cout
<< numbers.at(0)
<< std::endl;
return 0;
}
at()を使うと、範囲外アクセスが検出され、例外が送出されます。
一方、operator[]は通常、範囲チェックを保証しません。
C#の配列
int[] numbers = { 10, 20, 30 };
Console.WriteLine(numbers[0]);
C#では、配列の範囲外にアクセスすると、通常IndexOutOfRangeExceptionが発生します。
不正なメモリ領域へそのままアクセスするのではなく、実行時エラーとして検出されます。
文字列の違い
文字列の扱いも、言語ごとに異なります。
C言語の文字列
C言語には、C#のstringのような文字列オブジェクト型はありません。
一般的には、ヌル文字で終端された文字配列を文字列として扱います。
char name[] = "Taro";
メモリ上では、最後に\0が含まれています。
'T' 'a' 'r' 'o' '\0'
文字列を操作する際には、バッファサイズを正しく管理する必要があります。
C++の文字列
C++では、std::stringを利用できます。
#include <string>
std::string name = "Taro";
name += " Yamada";
文字列の結合、比較、長さの取得などを簡単に行えます。
用途によっては、std::string_viewやC形式の文字列も利用されます。
C#の文字列
C#では、string型を利用します。
string name = "Taro";
name += " Yamada";
C#の文字列はイミュータブルです。
見た目上は文字列を変更しているように見えますが、実際には新しい文字列が作成され、変数の参照先が変更されています。
C++とC#は名前ほど近くない
C#という名前から、C++の後継言語だと誤解されることがあります。
しかし、C#はC++を単純に改良した言語ではありません。
文法上は似ている部分がありますが、次の点が大きく異なります。
- 実行方式
- メモリ管理
- 標準ライブラリ
- オブジェクトの寿命
- ポインタの扱い
- 開発環境
- 配布方法
- 型システム
C++の設計思想
C++では、次のような点が重視されます。
- 高い実行性能
- ハードウェアに近い制御
- プログラマーの自由度
- 抽象化と低レベル処理の両立
- 不要な実行コストを避けること
C#の設計思想
C#では、次のような点が重視されます。
- 開発効率
- 型安全性
- メモリ管理の自動化
- 標準ライブラリとの統合
- チーム開発のしやすさ
- Webや業務アプリの生産性
C++経験者がC#を学ぶ場合も、文法だけでなく、.NETの仕組みやガベージコレクション、非同期処理などを理解する必要があります。
初心者が学ぶならどれがよいか
どの言語から学ぶべきかは、目的によって異なります。
コンピューターの仕組みを深く学びたい場合
C言語が向いています。
変数、関数、配列、ポインタ、メモリ管理を通して、プログラムがコンピューター上でどのように動くのかを理解しやすくなります。
ただし、エラーの原因を特定しにくい場面も多いため、初心者にとって簡単な言語とは限りません。
高性能なソフトウェアやゲームを作りたい場合
C++が向いています。
次のような分野を目指す場合に有力です。
- Unreal Engine
- 3Dゲーム
- ロボット
- 画像処理
- 映像処理
- 金融システム
- ネイティブアプリ
ただし、3言語の中では学習範囲が最も広く、習得難易度も高い傾向があります。
Web、業務システム、Unityを開発したい場合
C#が向いています。
メモリ管理をガベージコレクターに任せられ、標準ライブラリや開発ツールも充実しています。
比較的早い段階から、Webアプリ、業務システム、ゲームなどの実用的なプログラムを作りやすい言語です。
目的別の選び方
| 目的 | 適している言語 |
|---|---|
| コンピューターの仕組みを理解したい | C |
| マイコンを扱いたい | C |
| 組み込み開発をしたい | C、C++ |
| OSやドライバを開発したい | C、C++ |
| Unreal Engineを使いたい | C++ |
| Unityを使いたい | C# |
| Windowsアプリを作りたい | C# |
| 業務システムを作りたい | C# |
| Web APIを作りたい | C# |
| 高性能なゲームを作りたい | C++ |
| 低遅延の金融システムを作りたい | C++ |
| CADや映像処理ソフトを作りたい | C++ |
| 比較的早くアプリを作りたい | C# |
| メモリ管理を深く理解したい | C、C++ |
| 複数のプログラミング手法を学びたい | C++ |
よくある誤解
C言語、C++、C#には、いくつかよくある誤解があります。
C++はC言語の完全な上位互換である
C++はC言語と共通する文法を多く持ちますが、完全な上位互換ではありません。
Cでは有効でも、C++ではエラーになるコードがあります。
たとえば、Cではvoid*から他のポインタ型へ暗黙変換できますが、C++では通常、明示的な変換が必要です。
また、現代的なC++では、C言語風のコードをそのまま書くよりも、標準コンテナ、RAII、スマートポインタなどを利用する方が適切です。
C#はC++より常に遅い
C#がC++より必ず遅いとは限りません。
C++は、メモリ配置や処理コストを細かく制御できるため、低遅延処理やリアルタイム処理で有利になりやすい言語です。
一方、C#もJITやAOTによって高い性能を発揮します。
Webアプリや業務システムでは、言語の実行速度よりも、データベース、ネットワーク、アルゴリズム、設計の方が性能へ大きく影響する場合があります。
C#はWindows専用である
現在のC#と.NETは、Windowsだけでなく、LinuxやmacOSでも利用できます。
また、Dockerやクラウド環境でも動作します。
ただし、Windows FormsやWPFなど、一部のフレームワークはWindows向けです。
C#自体がクロスプラットフォームでも、使用するフレームワークによって対応OSが異なる点には注意が必要です。
C言語は古いので使われていない
C言語は歴史の長い言語ですが、現在も重要な分野で利用されています。
特に、次のような分野では欠かせない存在です。
- 組み込み
- OS
- 通信
- データベース
- マイコン
- ドライバ
- 言語処理系
- 高性能ライブラリ
古い言語であることと、実用性が低いことは同じではありません。
C言語・C++・C#の違いのまとめ
C言語、C++、C#は、名前は似ていますが、得意な分野と設計思想が異なります。
C言語
C言語は、コンピューターを低いレベルで効率的に制御することに向いています。
実行性能と自由度が高い一方で、ポインタやメモリ管理に関する知識が必要です。
OS、マイコン、組み込みシステムなどを開発する場合に適しています。
C++
C++は、高い実行性能と大規模なソフトウェア設計を両立するための言語です。
低レベル制御、オブジェクト指向、テンプレート、RAIIなど、多くの機能を持っています。
非常に強力ですが、言語仕様が広く、習得には時間がかかります。
ゲームエンジン、映像処理、CAD、ロボット、金融システムなどに向いています。
C#
C#は、安全性と開発効率を重視した.NET向けの言語です。
ガベージコレクション、充実した標準ライブラリ、優れた開発環境を利用できます。
Web、業務システム、クラウド、Unityによるゲーム開発などに適しています。
目的別に選ぶことが重要
言語選びで迷った場合は、次の基準で考えると分かりやすいでしょう。
- マイコン、OS、組み込みに関心があるならC言語
- Unreal Engine、高性能ゲーム、映像処理ならC++
- Unity、Web、業務システム、クラウドならC#
プログラミング初心者が、まず実用的なアプリケーションを作りたい場合は、C#が比較的始めやすい選択肢です。
一方、コンピューター内部の仕組みやメモリ管理を深く理解したい場合は、C言語を学ぶ価値があります。
高い実行性能と高度なソフトウェア設計の両方を身に付けたい場合は、C++が有力な選択肢です。
以上、C言語とC++とC#の違いについてでした。
最後までお読みいただき、ありがとうございました。
