ブロック (C言語拡張)

ブロック (Blocks) はAppleによるC言語、Objective-C、C++用の非標準の拡張であり、ラムダ式風の構文を用いてクロージャを作成する機能を提供する。ブロックはMac OS X 10.6以降とiOS 4.0以降向けのプログラムでサポートされるが、サードパーティ製ランタイムでMac OS X 10.5及びiOS 2.2以降でも使用可能である。

ブロックは、Grand Central Dispatchスレッディングアーキテクチャーをより容易に記述できるようにするという明確な目的でアップルによって設計された一方で、そのアーキテクチャーから独立して他のプログラミング言語のクロージャに類似した方法で使用することもできる。アップルはブロックをGNUコンパイラコレクションの自社のブランチとClang LLVMコンパイラフロントエンドに実装している。ブロックの言語ランタイムライブラリサポートはLLVMプロジェクトの一部で利用可能である。クロノスグループはブロック構文をOpenCLのバージョン2.0よりエンキューカーネルに使用している。

関数定義のように、ブロックは引数を持ち、内部でローカル変数を宣言することができる。一方で通常の関数定義とは違い、値は周囲のコンテキストから状況をとることもできる。ブロック定義はブロック内のコードへの参照及びその定義時のローカルのスタック変数の現在のスナップショットが含まれる不透明な値を生成する。ブロックは関数ポインタと同様に呼び出すことができる。

ブロックは変数に割り当てられたり、関数を越えたり、通常の関数ポインタのように使われるが、ブロックの範囲外で定義されたものを使用する際は特殊な演算子(Block_copy)でマークする必要がある。

ブロック値を与えると、ブロック内のコードは関数を呼び出す際と同じ構文を使用して、任意の時点で実行することができる。

例 
周囲のスコープに可変のステートを取り出す簡単な例として、整数範囲イテレータがあげられる。
#include <stdio.h>
#include <Block.h>
typedef int (^IntBlock)();

IntBlock MakeCounter(int start, int increment) {
	__block int i = start;
	
	return Block_copy( ^ {
		int ret = i;
		i += increment;
		return ret;
	});
	
}

int main(void) {
	IntBlock mycounter = MakeCounter(5, 2);
	printf("1回目: %d\n", mycounter());
	printf("2回目: %d\n", mycounter());
	printf("3回目: %d\n", mycounter());
	
	/* ブロックオブジェクトがコピーされているため、開放する必要がある。 */
	Block_release(mycounter);
	
	return 0;
}
/* 出力:
	1回目: 5
	2回目: 7
	3回目: 9
*/

コンパイル 
Linuxでは以下のとおりである。
clang -fblocks blocks-test.c -lBlocksRuntime

GCCの入れ子関数との関係 
ブロックは入れ子関数を文法的にサポートするためのC言語のGCC拡張に表面的には似ている。しかしながら、ブロックとは違い、GCCの入れ子関数では内部に持ったスコープが終了したあとは呼び出すことができない。

また、GCCスタイルの入れ子関数は入れ子関数のアドレスを取得する際に、実行可能なサンク(Thunk)を動的に生成する必要がある。x86も含めたほとんどのアーキテクチャはこれらのサンクをスタックに生成し、スタックは実行可能に設定する必要がある。実行可能スタックは一般的に潜在的なセキュリティホールと考えられている。ブロックは実行可能サンクを必要としないため、この弱点を持たない。

関連項目 
 クロージャ
 スコープ (プログラミング)
 ラムダ式
 XNU
 C++11（ラムダ式を含む）

参考文献

外部リンク 
 
 

C言語
サブルーチン