「structハック (struct hack) - Flexible array member」の編集履歴(バックアップ)一覧に戻る

structハック (struct hack) - Flexible array member - (2011/12/02 (金) 05:42:45) のソース

*structハック(struct hack) - Flexible array member
-"hack"という単語に弱いあなたへ。
-ここのページ書き加えたい。

**struct hack
-"Flexible array member(柔軟な配列のメンバ)"と呼ばれることが公の場では多いみたい。
-でも、ちょっと長いから"struct hack"の愛称で親しまれてる。以降の文章は"structハック"と書こうかな。

**structハックって?
-通常、要素数を定義しない配列の宣言は不完全な宣言とみなされコンパイルエラーとなります。
	int eureka[7];	//おっけー
	int renton[];	//コンパイルエラー
-しかし、構造体の宣言の最後の行に要素数を定義しない配列を宣言することができます。
	struct EurekaSeven
	{
		int eureka[7];
		int renton[];	//定義できちゃう!
	}
-これが&bold(){structハック}です。
-ここでの「renton」を&bold(){flexible array member(柔軟な配列のメンバ)}と言います。
-構造体だけでなく、共用体やclassでも同様のことができます。

***サイズと確保のされ方
	std::cout << sizeof(EurekaSeven) << std::endl;  // "28"と表示されるよん
-EurekaSeven構造体のサイズは"28"Byte。int型は"4"Byteなので、「4 Byte * eureka[7] = 28 Byte」。
-つまり、コンパイラは「int renton[];」をサイズ0の配列とみなしているのです。
	EurekaSeven es;
	for(int i=0; i < 7; ++i){
		std::cout << es.eureka+i << std::endl;
	}
	std::cout << es.renton << std::endl;
-上のプログラムを行うと、それぞれどこに確保されているかアドレスを見ることができます。
	//出力結果
	002FFB94	//es.eureka[0];
	002FFB98	//es.eureka[1];
	002FFB9C	//es.eureka[2];
	002FFBA0	//es.eureka[3];
	002FFBA4	//es.eureka[4];
	002FFBA8	//es.eureka[5];
	002FFBAC	//es.eureka[6];
	002FFBB0	//es.renton[];


**こんなのどこで使うの?	
	int const elements	= 156;
	void *esMemoryPool	= std::malloc( sizeof(struct EurekaSeven) + sizeof(int[elements]) );
	struct EurekaSeven *es	= new(esMemoryPool) EurekaSeven;
-このようにして使うことが多いみたいです。
-何をしているのかというと、次と同じようなことをしています。
	struct EurekaSeven
	{
		int eureka[7];
		int renton[elements];
	};
-int renton[]を使うことで、renton[0]~renton[155]へ簡単にアクセスすることができるようになります。
	es->renton[155] = 777;
	std::cout << *((es->renton)+155) << std::endl;  //"777"が表示される。
***templateを使って同様のことができます。
	template <unsigned int N>
	struct EurekaSeven
	{
		int eureka[7];
		int renton[T];
	};
-ただし、templateを使って要素数を定義する場合、要素数の違いで型が変わってしまいます。
	int const elements		= 156;
	EurekaSeven<elements> *es 	= new EurekaSeven<elements>;
	delete (es);
-EurekaSeven<156>型とEurekaSeven<256>型は違う型なので代入したりできません。


**使い方
	#include <new>
	#include <iostream>
 
	struct EurekaSeven
	{
		int eureka[7];
		int renton[];
	};
 
	int main()
	{
		int const elements	= 156;
		void *esMemoryPool	= std::malloc( sizeof(struct EurekaSeven) + sizeof(int[elements]) );
		struct EurekaSeven *es	= new(esMemoryPool) EurekaSeven;
		es->renton[155]		= 777;
		std::cout << *((es->renton)+155) << std::endl;
		delete (es, esMemoryPool);
 
		return 0;
	}
-placement newしているので、<new>をincludeしてあげてください。

***structハックをVisual C++2010で使うと以下のような警告がでます。
  warning C4200: 非標準の拡張機能が使用されています : 構造体または共用体中にサイズが 0 の配列があります。
  UDT にサイズが 0 の配列が含まれているときに、copy-ctor または copy-assignment オペレーターを生成することはできません。


**参考文献
-[[Sun Studio 12: C ユーザーズガイド - D.1.8 柔軟な配列のメンバー>http://download.oracle.com/docs/cd/E19205-01/820-1209/bjazj/index.html]]
-[[http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf]](p.103 - §6.7.2.1 17のEXAMPLE)
記事メニュー
目安箱バナー