キャストだらけのプログラム

型制約の厳しい言語では必要に応じて強制的な型変換(キャスト: Cast)が必要となり、それがまたバグの温床であるらしいのです。

C言語では簡単に型を(  )でくくるにことにより、このキャストが可能です。しかし、これはあまりにも簡単過ぎ、安易に行ってしまいますし、後でバグとりの時に発見しにくい、という副作用もあるらしいのです。

これに対して、C++ではややこしい構文をわざと使用せねばなりません。これにより、プログラマに対して心理的圧迫を与え、何とかしてキャストを使用せずにもっとスマートなプログラムを書くように暗黙的に強制します。また、バグ発見もこの構文を探すことにより、より容易にできる、このような利点が言われています。

こんなこと、自分ごときが書く小さなプログラムでは関係無いよ、そのように今まで思っていましたが、先の、DHTをサーチして、そのアドレスを可変配列Vectorに収納し、後から、そのアドレス近傍の内容を表記するプログラムを書いた時に、そのキャストの嵐に会いました。

  1.     std::vector <u_short *> address;
  2.     // u_charへのポインタをいれるvectorを宣言した
  3.     u_short *buffer = new u_short[bufSize/2]; 
  4.     // ワードずつ確保なので半分
  5.     u_short * const bufTop = buffer;
  6.     u_short * const bufEnd = bufTop + bufSize/2;
  7.     u_short *bufPntr = bufTop;
  8.     // 動き回るポインターを先頭にセット
  9.     fp.read(reinterpret_cast<char *> (buffer), bufSize);
  10.     // ここではバイト単位でしか指定できないのでキャストする
  11.     while (bufPntr < bufEnd) {
  12.         if (*bufPntr == 0xC4FF) {
  13.             // Little Endianに注意!!
  14.             // DHT tagにヒットした
  15.             address.push_back(bufPntr);
  16.         }
  17.         bufPntr++;
  18.     }
  19.     fp.close();
  20.     u_char * bufferByte;
  21.     // これでvector<u_short *> addressにDHTアドレスが格納された
  22.     std::vector<u_short *>::iterator it;;
  23.     for (it = address.begin(); it != address.end(); ++it) {
  24.         std::cout << std::hex << (int)*reinterpret_cast<u_char *> (*it) << ” “;
  25.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 1)) << ” “;
  26.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 2)) << ” “;
  27.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 3)) << ” “;
  28.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 4)) << ” “;
  29.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 5)) << ” “;
  30.         std::cout << static_cast<int>(*(reinterpret_cast<u_char *> (*it) + 6)) << ” “;
  31.         std::cout << (int)*(reinterpret_cast<u_char *> (*it) + 7) << ” “;
  32.         std::cout << (int)*(reinterpret_cast<u_char *> (*it) + 8) << ” “;
  33.         std::cout << (int)*(reinterpret_cast<u_char *> (*it) + 9) << ” “;
  34.         std::cout << (int)*(reinterpret_cast<u_char *> (*it) + 10) << std::endl;
  35.         std::cout << ” : “ << (int)*(bufferByte + 4) << std::endl;
  36.     }

こんなことになると、流石に自分の書いているプログラムは改良の余地がたくさんあるぞ、ということを思い知らされますよね。要するに、バイト単位で動かねばならないところを、わざわざワード単位で書いているからこんなことになるのでしょう。流石に31行から35行ではたまらなくなり、C言語のキャスト構文 (int)を static_cast<int>のかわりに使ってしまいました。
これもC++の新しいキャスト構文のお蔭様様ですかね。

これから羽田空港

今 羽田空港に移動中です。途中病院に寄り、昨日の TAVIの患者さん達の具合を伺ってきました。お二人ともお元気で、この治療法のすばらしさがまたしても証明されました。

昨日技術的に学んだことですが、我々が使用しているシステムは Self-expandableのものです。もちろんシースによりプロテクトされており、体温により温まった Nitinol合金姓のステントが大動脈基部で自然に拡張することにより、固定されます。頭の中では、その部位でシースを抜けば良い、これだけです。簡単なことです。

しかし、患者さんの体内では話が異なります。

  1. 心臓が強く拍動している – これに対しては rapid pacingである程度対応します
  2. 大腿動脈アプローチの場合には、長い経路、しかも大動脈弓で強く屈曲しているため、その部位で保護シースと大動脈との摩擦抵抗が大きい、しかもこれも心拍動により変化する
  3. 同様の理由により保護シースとステントの間の摩擦抵抗も大きい
  4. 同様の理由によりシステムと、stiff wireとの間の抵抗も大きい

実際の植え込みでは、これらの相反するいくつもの効力に逆らって指摘部位で植え込みを行わねばならないのです。そながら作用反作用をうまいこと魔法のようにコントロールすることが必要なのです。これにはどうやらセンスと経験が必要な気がします。それにようやく気が付いたのです。これはPCIとは全く異なる世界です。術者として技術的な部分で非常に惹かれる部分がありますし、自分にとってのチャレンジでもあります。

DICOM XAハフマン解析

DICOM XAのファイルを Binary Editorで調査すると どうやら 一コマ静止画の集まりのようです。


以上のように、SOIに始まり、内部にDHTを含み、それに引き続いてSOF3があり、最後にEOIで終わるブロックが一コマとなります。

ちなみに、JPEG規約により、soi = 0xFFD8, DHT = 0x FFC4, SOF3 = 0xFFC3, EOI = 0xFFD9なのです。ちなみに、それぞれ Start of Image, Define Huffman Table, start of Frame 3 = Lossless, End of Imageのことです。

手持ちのDICOM XA fileを調べると、SOIからEOIのブロックに 149.646KBぐらいが含まれていました。1 pixel = 8 bitsの濃度とすれば、1 Frame = 512 x 512 pixelとすれば、262.144 KBのデータ量ですので、42%までデータが圧縮されたことになります。

プログラムとしては、SOF3の次から、EOIの前までをイメージ圧縮データと考え、DHTより求めた解読表に沿って解読すれば良いことになりそうです。