第21章 ポインタを使用できる「安全でないコード」:連載 改訂版 C#入門(4/4 ページ)
連載最終回となる今回は、C#におけるポインタの利用について解説する。ポインタのサポートにより、C#では低レベルな処理も効率よく行うことができる。
21-9 「安全でないコード」が本当にほしくなる事例
以下は、「安全でないコード」が本当にほしくなる事例として作成したものである。24ビットのBMPファイルを読み込んで、ネガ反転処理を行うものである。まず、.NET Frameworkのクラス・ライブラリを活用した正統派のソースList 21-9を見ていただこう。
1: using System;
2: using System.IO;
3: using System.Drawing;
4:
5: namespace Sample009
6: {
7: using System.IO;
8: using System.Drawing;
9: class Class1
10: {
11: private static void NegativeBMP( string inputFileName, string outputFileName )
12: {
13: Bitmap bitmap = new Bitmap( inputFileName );
14: for( int y=0; y<bitmap.PhysicalDimension.Height; y++ )
15: {
16: for( int x=0; x<bitmap.PhysicalDimension.Width; x++ )
17: {
18: Color c = bitmap.GetPixel( x, y );
19: bitmap.SetPixel( x, y, Color.FromArgb((byte)~c.R, (byte)~c.G,(byte)~c.B) );
20: }
21: }
22: bitmap.Save( outputFileName );
23: }
24: [STAThread]
25: static void Main(string[] args)
26: {
27: DateTime start = DateTime.Now;
28: const string inputFileName = "c:\\test1.bmp";
29: const string outputFileName = "c:\\test2.bmp";
30: NegativeBMP( inputFileName, outputFileName );
31: DateTime end = DateTime.Now;
32: Console.WriteLine( end-start );
33: }
34: }
35: }
次に、「安全でないコード」を用いた例、List 21-10を見ていただこう。
1: using System;
2: using System.IO;
3: using System.Runtime.InteropServices;
4:
5: namespace Sample010
6: {
7: [StructLayout(LayoutKind.Sequential,Pack=1)]
8: struct BITMAPFILEHEADER
9: {
10: public ushort bfType;
11: public uint bfSize;
12: public ushort bfReserved1;
13: public ushort bfReserved2;
14: public uint bfOffBits;
15: }
16: [StructLayout(LayoutKind.Sequential,Pack=1)]
17: struct BITMAPINFOHEADER
18: {
19: public uint biSize;
20: public int biWidth;
21: public int biHeight;
22: public ushort biPlanes;
23: public ushort biBitCount;
24: public uint biCompression;
25: public uint biSizeImage;
26: public int biXPelsPerMeter;
27: public int biYPelsPerMeter;
28: public uint biClrUsed;
29: public uint biClrImportant;
30: public const int BI_RGB = 0;
31: };
32:
33: class Class1
34: {
35: unsafe private static void NegativeBMP( string inputFileName, string outputFileName )
36: {
37: FileStream inputFile = new FileStream(inputFileName,FileMode. Open);
38: byte [] fileImage = new byte[inputFile.Length];
39: inputFile.Read(fileImage,0,(int)inputFile.Length);
40: inputFile.Close();
41:
42: fixed( byte * basePtr = &fileImage[0] )
43: {
44: BITMAPFILEHEADER * bitmapFileHeader = (BITMAPFILEHEADER *)basePtr;
45: BITMAPINFOHEADER * bitmapInfoHeader = (BITMAPINFOHEADER * )(basePtr + sizeof(BITMAPFILEHEADER));
46: byte * bits = basePtr + bitmapFileHeader->bfOffBits;
47: if( bitmapInfoHeader->biBitCount != 24 || bitmapInfoHeader->biCompression != BITMAPINFOHEADER.BI_RGB )
48: {
49: Console.WriteLine( "Error: 24bit RGB Bitmap Only");
50: return;
51: }
52: int bytesInLine = (bitmapInfoHeader->biWidth+3)/4*4;
53: int totalBytes = bytesInLine * bitmapInfoHeader->biHeight * 3;
54: for( int i = 0; i<totalBytes; i++ )
55: {
56: *bits = (byte)~*bits;
57: bits++;
58: }
59: }
60:
61: FileStream outputFile = new FileStream(outputFileName,FileMode.Create);
62: outputFile.Write(fileImage,0,fileImage.Length);
63: outputFile.Close();
64: }
65: [STAThread]
66: static void Main(string[] args)
67: {
68: DateTime start = DateTime.Now;
69: const string inputFileName = "c:\\test1.bmp";
70: const string outputFileName = "c:\\test2.bmp";
71: NegativeBMP( inputFileName, outputFileName );
72: DateTime end = DateTime.Now;
73: Console.WriteLine( end-start );
74: }
75: }
76: }
List 21-9とList 21-10のどちらを実行しても、Fig.21-10の画像をFig.21-11のように加工する。どちらも同じ結果になる。
さて、ソースを見比べれば、正統派の方がずっと短く読みやすいことが分かるだろう。しかも、正統派のソースは、24ビットBMPに制限されず、Bitmapクラスがサポートするあらゆるデータ型を扱える。それにもかかわらず、「安全でないコード」がほしくなる理由は、圧倒的な性能差にある。Pentium 4/1.5GHzのマシンでの処理に、正統派のコードは23秒を必要としたが、「安全でないコード」版の方は0.4秒ほどで済んだ。Fig.21-12は、サンプル・ソースを実行した所要時間を示している。上が正統派のソースの場合で、下が「安全でないコード」を使用したソースの場合である。
もちろん、ここで取り上げた正統派のソースはあまりにも愚直すぎるので、「安全でないコード」を使わなくても、低レベルの処理に置き換えることでかなりの高速化を行うことは可能だ。例えば、byte配列で一気に反転処理を行えば、性能面で大差ないコードを書くこともできるだろう。しかし、このような単純な処理で済まない場合、型を持ったポインタを使用できる「安全でないコード」の方が、よりエレガントに問題を解決できるだろう。
『新プログラミング環境 C#がわかる+使える』
本記事は、(株)技術評論社が発行する書籍『新プログラミング環境 C#がわかる+使える』から許可を得て一部分を転載したものです。
【本連載と書籍の関係について 】
この書籍は、本フォーラムで連載した「C#入門」を大幅に加筆修正し、発行されたものです。連載時はベータ版のVS.NETをベースとしていましたが、書籍ではVS.NET製品版を使ってプログラムの検証などが実施されています。技術評論社、および著者である川俣晶氏のご好意により、書籍の内容を本フォーラムの連載記事として掲載させていただけることになりました。
→技術評論社の解説ページ
ご注文はこちらから
Copyright© Digital Advantage Corp. All Rights Reserved.