bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] CIL を読む理由と基本文法を理解する

[C#] CIL を読む理由と基本文法を理解する

Jul 11, 2026 C# , .NET bucket-sort

今回から数回に分けて、C# のコンパイル結果である CIL を扱います。

C# のコードは、ビルドするといきなり CPU が直接実行する機械語になるわけではありません。
まず .NET ランタイムが理解できる中間表現へ変換され、実行時に JIT コンパイラーによってネイティブコードへ変換されます。

この記事では、CIL を読む理由、基本的な構文、命令とスタックの関係を見ていきます。

CIL を学ぶ理由

普通のアプリケーション開発では、CIL を直接書くことはほとんどありません。
それでも CIL を読む力があると、C# と .NET の理解が一段深くなります。

たとえば、次のような場面で役立ちます。

  • C# の構文が実行時にどう表現されるかを理解する
  • 値型、参照型、ボックス化、仮想呼び出しなどの仕組みを確認する
  • リフレクションや属性がどのようにメタデータへ保存されるかを理解する
  • パフォーマンス上の違いを調べる
  • 逆コンパイルツールの出力を読めるようにする
  • 動的にコードを生成する仕組みを理解する

CIL は毎日書くものではありません。
ただし、読めるようになると「C# の裏側で何が起きているのか」を説明できるようになります。

C# から CIL への流れ

次のような C# コードを考えます。

public static int Add(int x, int y)
{
    return x + y;
}

これをビルドすると、概念的には次のような CIL になります。

.method public hidebysig static int32 Add(int32 x, int32 y) cil managed
{
  .maxstack 2
  ldarg.0
  ldarg.1
  add
  ret
}

細かい出力はビルド設定やコンパイラーによって変わります。
ただし、意味としては「引数をスタックへ積む」「加算する」「戻る」という流れです。

CIL の大まかな構成

CIL のテキスト表現には、主に次のような要素が出てきます。

ディレクティブ

. で始まる宣言です。
アセンブリ、クラス、メソッド、ローカル変数、スタックサイズなどを表します。

.assembly Sample {}
.class public auto ansi beforefieldinit Calculator
.method public hidebysig static int32 Add(int32 x, int32 y) cil managed
.maxstack 2

ディレクティブは「構造を宣言するもの」と考えると分かりやすいです。

属性

CIL 上にも、型やメソッドの性質を表す指定が現れます。
たとえば public、static、private、specialname などです。

.method public hidebysig specialname rtspecialname 
        instance void .ctor() cil managed

C# のアクセス修飾子やメンバーの性質が、CIL 上ではこのような形で表現されます。

命令

実際に実行される操作です。

ldarg.0
ldarg.1
add
ret

ldarg.0 は 0 番目の引数を評価スタックへ積みます。
add はスタック上の値を取り出して加算し、結果を再びスタックへ積みます。
ret は戻り値を返してメソッドを終了します。

命令名と実際の命令コード

CIL では、命令を人間が読みやすい名前で表します。

ldc.i4.1
ldc.i4.2
add
ret

これらの名前は、実際のバイナリ上では数値の命令コードとして保存されます。
人間が読む .il では名前で表示され、アセンブリの中ではより低レベルな表現になっています。

通常の学習では、命令名を読めれば十分です。
数値の命令コードまで覚える必要はありません。

CIL はスタックベースで動く

CIL を読む上で最重要なのは、評価スタックです。

C# の式は、CIL では値をスタックへ積んだり、取り出したりしながら処理されます。

次の C# コードを考えます。

int result = 10 + 20;

概念的には、次のような CIL になります。

ldc.i4.s 10
ldc.i4.s 20
add
stloc.0

スタックの動きは次の通りです。

ldc.i4.s 10   -> 10 を積む
ldc.i4.s 20   -> 20 を積む
add           -> 20 と 10 を取り出して加算し、30 を積む
stloc.0       -> 30 をローカル変数 0 番へ格納する

CIL では、多くの命令が「スタックから値を取る」「結果をスタックへ積む」という形で動きます。

スタック操作の小さな例

次の C# メソッドを見てみます。

public static int MultiplyAndAdd(int x, int y)
{
    return (x * y) + 10;
}

概念的な CIL です。

.method public hidebysig static int32 MultiplyAndAdd(int32 x, int32 y) cil managed
{
  .maxstack 2
  ldarg.0
  ldarg.1
  mul
  ldc.i4.s 10
  add
  ret
}

流れを追うと、こうなります。

ldarg.0      -> x を積む
ldarg.1      -> y を積む
mul          -> x と y を取り出して掛け算し、結果を積む
ldc.i4.s 10 -> 10 を積む
add          -> 掛け算の結果と 10 を加算する
ret          -> 結果を返す

この「値を積む、使う、結果を積む」という見方ができると、CIL はかなり読みやすくなります。

往復的に理解する

CIL を学ぶときは、C# と CIL を往復しながら読むのが効果的です。

public static bool IsEven(int value)
{
    return value % 2 == 0;
}

概念的な CIL です。

ldarg.0
ldc.i4.2
rem
ldc.i4.0
ceq
ret

流れは次の通りです。

引数 value を積む
2 を積む
剰余を計算する
0 を積む
等しいか比較する
結果を返す

このように、C# の構文を CIL に置き換えてみると、演算子や比較の実体が見えてきます。

CIL を確認する方法

ビルド済みアセンブリの中身を確認するには、逆コンパイルツールを使うのが手軽です。

代表的には ILSpy などがあります。
C# 風のコードへ戻して表示するだけでなく、CIL の表示もできます。

また、.il ファイルを作って ilasm で組み立てる方法もあります。
ただし、日常の .NET 開発では、CIL を手でコンパイルするよりも「読むため」に使うことが多いです。

まとめ

CIL は、C# と CLR の間にある中間表現です。
普段は直接書きませんが、読めるようになると、C# の構文が実行時にどう扱われるかを理解しやすくなります。

最初に押さえるべきポイントは、ディレクティブ、属性、命令、そして評価スタックです。
次回は、CIL 上でアセンブリ、名前空間、クラス、インターフェイス、構造体、列挙型、ジェネリック型がどのように定義されるかを見ていきます。

C# .NET CIL IL CLR アセンブリ 中間言語
← [C#] dynamic と式木で動的な呼び出しを理解する [C#] CIL で型とメンバーがどう表現されるか →

Related Posts

  • [C#] CIL の命令とスタック動作を読み解く Jul 13, 2026
  • [C#] CIL で型とメンバーがどう表現されるか Jul 12, 2026
  • [C#] .NET アセンブリの構造とライブラリの種類を理解する Jul 1, 2026
  • [C#] 実行時にアセンブリを生成する Jul 14, 2026

Table of Contents

  • CIL を学ぶ理由
  • C# から CIL への流れ
  • CIL の大まかな構成
    • ディレクティブ
    • 属性
    • 命令
  • 命令名と実際の命令コード
  • CIL はスタックベースで動く
  • スタック操作の小さな例
  • 往復的に理解する
  • CIL を確認する方法
  • まとめ

Recent Posts

  • [C#] EF Core でデータベースの準備と初期データを扱う Aug 8, 2026
  • [C#] EF Core とリポジトリでデータ操作を整理する Aug 7, 2026
  • [C#] DbContext の設定と保存処理を拡張する Aug 6, 2026
  • [C#] EF Core のエンティティと表示用モデルを設計する Aug 5, 2026
  • [C#] EF Core を中心にデータアクセス層を分ける Aug 4, 2026

Categories

  • C#150
  • .NET149
  • AWS27
  • Laravel16
  • Entity Framework Core15
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • Data Access6
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • Entity Framework Core
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • LINQ
  • System.Collections.Generic
  • デリゲート
  • リフレクション
  • ADO.NET
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メタデータ
  • メモリ管理
  • CIL
  • DoS
  • Nginx
  • SQL Server
  • WordPress
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • アセンブリ
  • インターフェース
  • オブジェクト指向
Powered by Hugo & Explore Theme.