<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5416910919127317318</id><updated>2024-09-29T10:01:56.834+09:00</updated><category term="ソース"/><category term="C++"/><category term="Visual Studio"/><category term="Win32 API"/><category term="ゲーム"/><category term="コマンドプロンプト"/><category term="C"/><category term="アルゴリズム"/><category term="テンプレート"/><category term="紹介"/><category term="Mac"/><category term="OS X"/><category term="お知らせ"/><category term="日記"/><category term="最適化"/><category term="駄文"/><title type='text'>ほげほげーむ</title><subtitle type='html'>コマンドプロンプトからiPhoneアプリまで、&#xa;なんかつくる。ほげほげーむ。</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-8434616730084252317</id><published>2013-06-27T23:16:00.000+09:00</published><updated>2013-06-27T23:39:55.762+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mac"/><category scheme="http://www.blogger.com/atom/ns#" term="OS X"/><category scheme="http://www.blogger.com/atom/ns#" term="日記"/><title type='text'>MacBook Pro 17inch Early 2011をSSD(6Gbps)に換装</title><content type='html'>&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;■　事の背景というかあらすじ&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
日頃から気分転換して作業したいなーとか&lt;br /&gt;
手軽なマシン無いかなーとか&lt;br /&gt;
MackBook Air（以下MBA）持ってないなーとか&lt;br /&gt;
ほしーなーとか、&lt;br /&gt;
よこせよーくれくれーおらーとか思ってたのですが、&lt;br /&gt;
&lt;br /&gt;
最近発売されたMBAがあんまり魅力的だったので、&lt;br /&gt;
テヘペロッて感じで購入しました。&lt;br /&gt;
&lt;br /&gt;
最新のMBAのなにが良いと言えば、&lt;br /&gt;
・CPUがHaswellで1日作業に耐えうるバッテリー(12時間)&lt;br /&gt;
・IEEE 802.11acに対応で、環境さえあればWi-Fi接続が1Gbps超える&lt;br /&gt;
・USB3.0がデフォ。Thunderboltにも対応&lt;br /&gt;
・SSDの接続規格がSATA6Gbpsを更に超えるPCIe&lt;br /&gt;
という凄まじきスペックで、&lt;br /&gt;
持ち運べるノートが欲しいなら買うしか無いレベルだったというわけですが、&lt;br /&gt;
その中でもSSDすごいなーっていう。&lt;br /&gt;
いや、Haswellも相当すごいんですが。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初めてSSD搭載機を所持したわけですが、やっぱりほんと早いんですね。&lt;br /&gt;
スリープから画面が立ち上がるまでに1秒くらい。&lt;br /&gt;
で、すごいなーすごいなーと言って触ってる横には、&lt;br /&gt;
メインマシンであるMacBook Pro（以下MPB）が(´・ω・｀)ｼｮﾎﾞｰﾝとしていたわけです。&lt;br /&gt;
&lt;br /&gt;
さてそのMBP、&lt;br /&gt;
環境としてどう使っているかといえば、&lt;br /&gt;
・Xcodeでプログラミング＆シミュレータでhogehoge&lt;br /&gt;
・偶にCubaseで音楽制作&lt;br /&gt;
・Parallels（CPU2コア、ドライブ80GB、メモリ3GB割り当て）&lt;br /&gt;
・同Windows 8 ProでPhotoshop CS4 Extended&lt;br /&gt;
・同Windows 8 ProでVisual Studio 2010 Express&lt;br /&gt;
・同Windows 8 Proで偶にゲーム&lt;br /&gt;
&lt;br /&gt;
流石にこれだけやるとメモリ8GBでは使いきってしまって、&lt;br /&gt;
もう無理と思って16GBにしましたが、下手をするとギリギリまで行きます。&lt;br /&gt;
（普段は空き4GB〜8GB程度）&lt;br /&gt;
Parallelsで3GB以上メモリを食べちゃうので、まあそんなもんです。&lt;br /&gt;
&lt;br /&gt;
で、購入して3ヶ月くらいでMBPのメモリを変えたのは効果大で、&lt;br /&gt;
結構サクサクになったんですね。&lt;br /&gt;
まあただ、やっぱりParallelsとかの仮想環境は、&lt;br /&gt;
まあ・・・いいかな位にしか動かなかったんですね。&lt;br /&gt;
&lt;br /&gt;
今回のMBAのサクサクな動きをみて、&lt;br /&gt;
ああ、HDDのMBPもう無理だわってなって、精神的限界を迎えたので、&lt;br /&gt;
おもむろにSSD化だよね！ってなりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;■　作業対象について&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
タイトルにもありますが、以下MBPのスペック。&lt;br /&gt;
・&lt;b&gt;プロセッサ&lt;/b&gt; &amp;nbsp;2.2 GHz Intel Core i7&lt;br /&gt;
・&lt;b&gt;メモリ&lt;/b&gt; &amp;nbsp;16 GB 1333 MHz DDR3&lt;br /&gt;
・&lt;b&gt;ソフトウェア&lt;/b&gt; OS X 10.8.4（12E55）&lt;br /&gt;
・&lt;b&gt;ストレージ&lt;/b&gt; &lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;HDD 750GB&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
で、このHDDを&lt;a href=&quot;http://www.cfd.co.jp/ssd/s6tnhg5q.html&quot; target=&quot;_blank&quot;&gt;CSSD-S6T256NHG5Q&lt;/a&gt;というSSDに換装しました。&lt;br /&gt;
CFDの東芝製チップ採用のS6TNHG5Qシリーズってヤツです。&lt;br /&gt;
理論値として、&lt;br /&gt;
・Seq-Read 530MB/s&lt;br /&gt;
・Seq-Write 490MB/s&lt;br /&gt;
というハイスペック。ホントかいなー。&lt;br /&gt;
メーカー製品ページにもWinの定番CrystalDiskMarkによるベンチマーク結果ではほぼ公称スペックの結果が出てます。&lt;br /&gt;
6Gbpsでの接続というところがミソですね。&lt;br /&gt;
&lt;br /&gt;
で、このSSD、購入時点でネット上に成功例が無かったため、&lt;br /&gt;
面白そうなのでコレに決めた次第です。&lt;br /&gt;
多分、秋葉の有名なMac店のサイトの購入ページが要因にもなってると思います。&lt;br /&gt;
あそこには同時期のMBPの内、17インチモデルだけは動作保証外とあって、&lt;br /&gt;
私も最初はためらいました。&lt;br /&gt;
&lt;br /&gt;
まあでも、冒険でしょっ！( ゜∀゜)o彡&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;■　作業内容&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
換装の方法は正直今さら書いても仕方ないですね。&lt;br /&gt;
沢山の先人という名の人柱ブログが存在していますから、&lt;br /&gt;
検索すれば直ぐに出てきます。&lt;br /&gt;
&lt;br /&gt;
とりあえず、今回参考にさせて頂いたのは&lt;a href=&quot;http://rinare.com/20120721_512gb_ssd_on_macbook_pro_17inch_early2011_adata-asx900s3.html&quot; target=&quot;_blank&quot;&gt;こちらの記事&lt;/a&gt;。&lt;br /&gt;
ありがたやー(´・ω・｀)&lt;br /&gt;
&lt;br /&gt;
とりえずやることは、HDDに構築したシステムをSSDへ完全に移行すること。&lt;br /&gt;
大雑把な項目としては、&lt;br /&gt;
・SSDに換装する（上記リンク参照）&lt;br /&gt;
・Command&amp;nbsp;+ R押しでMacを立ち上げ、リカバリモードに入る&lt;br /&gt;
・タイムマシンかディスクユーティリティでSDDを初期化後データ移行&lt;br /&gt;
&lt;br /&gt;
なお、&lt;b&gt;リカバリモードは、ネットに繋がっていれば、&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;勝手にOSイメージをダウンロードしてきてくれます&lt;/b&gt;から、&lt;br /&gt;
先にSSDにOS Xをインストールとかはしなくて良かったです。&lt;br /&gt;
Macすごい！　感動しました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;■　作業で困ったことや注意点&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;span style=&quot;color: #990000;&quot;&gt;・【注意点１】トルクスドライバと2.5インチ外付けHDDケースを事前に用意！&lt;/span&gt;&lt;br /&gt;
　先人達のありがたい記事を流し読みするという愚行の結果、&lt;br /&gt;
　MBPの裏蓋を開けてから３時間ほど名古屋の大須商店街をさまよった末に、&lt;br /&gt;
　ドスパラ２Fと同ビル３Fにてトルクスドライバを含む、&lt;br /&gt;
　精密ドライバセットの入手に成功しました。（買ったのはは２Fで見つけたヤツ）&lt;br /&gt;
&lt;br /&gt;
　前日に久しぶりの運動をして筋肉痛と疲労がガッチンコしてました。&lt;br /&gt;
　トルクスドライバの旅に出たときにはアレな魚の眼でした。&lt;br /&gt;
　必要サイズは各ブログで言われている通り、&lt;b&gt;T6サイズ&lt;/b&gt;です。&lt;br /&gt;
&lt;br /&gt;
　取り出したシステムディスクを外付けHDDにするためには無論ケースが必要です。&lt;br /&gt;
　これも事前に購入します。安いところではUSB3.0対応で1000円もしないです。&lt;br /&gt;
　こっちはアメ横のツクモで780円のを買いました。&lt;br /&gt;
　いまはMBAにUSB3.0接続して快適に使用してます。&lt;br /&gt;
&lt;br /&gt;
　参考：荒ぶりながら買ったドライバセットはこんなヤツ↓&lt;br /&gt;
　&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcMBCBrcBXrCS9l6lLhGzvYIXunvzqWrrLWR_9U9ajVzv3XX0GIbrejXXZ1BbXbHBAz4uxz6B5OHC1ZkYc0aaXbxgA8dbjNcq6QTJ-s8SBFTbAemBo6ugmUWgBB0qDVy0MprY3XYfRLdM/s640/image.jpeg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcMBCBrcBXrCS9l6lLhGzvYIXunvzqWrrLWR_9U9ajVzv3XX0GIbrejXXZ1BbXbHBAz4uxz6B5OHC1ZkYc0aaXbxgA8dbjNcq6QTJ-s8SBFTbAemBo6ugmUWgBB0qDVy0MprY3XYfRLdM/s640/image.jpeg&quot; height=&quot;326&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #990000;&quot;&gt;・&lt;/span&gt;&lt;span style=&quot;color: #990000;&quot;&gt;【注意点２】&lt;/span&gt;&lt;span style=&quot;color: #990000;&quot;&gt;データ移行の際のタイムマシンとディスクユーティリティは取り扱い注意！&lt;/span&gt;&lt;br /&gt;
　HDDからSSDへのデータ移行には、２つの方法があります。&lt;br /&gt;
　一つはTime Machine（タイムマシン）をつかう方法、&lt;br /&gt;
　もう一つはディスクユーティリティの復元機能を使う方法です。&lt;br /&gt;
&lt;br /&gt;
　&lt;b&gt;タイムマシンデータを使った移行についての注意点。&lt;/b&gt;&lt;br /&gt;
　&lt;b&gt;タイムマシンは、基本的に初回バックアップのみフルで行ってくれます&lt;/b&gt;。&lt;br /&gt;
　&lt;b&gt;データ移行をする際は、フルバックアップのデータのみが対象です&lt;/b&gt;。&lt;br /&gt;
　よって、そのデータがないとタイムマシンは使えません。&lt;br /&gt;
　残念なことに、私の場合はフルバックアップしていたにも関わらず、&lt;br /&gt;
　そのデータを認識してくれませんでした。&lt;br /&gt;
　もしかしたら、USB2.0接続で外付けHDD化していたので、&lt;br /&gt;
　認識するのに時間がかかりまくっていたのかもしれませんが、&lt;br /&gt;
　耐え切れなかったので、ぶった斬・・・諦めました。&lt;br /&gt;
&lt;br /&gt;
　&lt;b&gt;ディスクユーティリティを使ってSSDへシステムを復元する方法の注意点。&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;　取り外したHDDのOS X（システム）のパーティションのサイズは、&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;　復元先のストレージの容量以下でなければ復元出来ません。&lt;/b&gt;&lt;br /&gt;
　&lt;b&gt;復元前にシステムディスクのパーティションサイズを変更する必要があります&lt;/b&gt;。&lt;br /&gt;
　（要数時間）&lt;br /&gt;
&lt;br /&gt;
　私の場合は、システムディスクを外付HDDとしてから、&lt;br /&gt;
　その上でパーティションサイズを変更しました。&lt;br /&gt;
　システム入りのパーティションの情報に少々不備があったらしく、&lt;br /&gt;
　パーティションサイズの変更を拒否されたため、&lt;br /&gt;
　試行錯誤していて、結局そうなりました。&lt;br /&gt;
&lt;br /&gt;
　また、Mac起動時に外付けにしたシステム入りのHDDを接続していると、&lt;br /&gt;
　どうも、パーティションに関わる操作を拒否られました。&lt;br /&gt;
　&lt;b&gt;外付けHDDの接続は、リカバリモードのメニュー画面が出てからで良い&lt;/b&gt;です。&lt;br /&gt;
&lt;br /&gt;
　これらが正しく行われていれば、復元機能を使い、全く同じ環境をSSDに移行できます。&lt;br /&gt;
　移行アシスタントよりも精度良いです。（これも要数時間）&lt;br /&gt;
　ただし、一部の認証付きのソフトウェアは再認証が必要な場合があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;■　結果報告&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
非常に快適です。&lt;br /&gt;
MBPがMBPの威厳を取り戻して、いまは(｀・ω・´)ｼｬｷｰﾝとしてます。&lt;br /&gt;
&lt;br /&gt;
動作保証とかは自己責任の世界なので元から気にしてませんが、&lt;br /&gt;
やってよかった感が凄いです。&lt;br /&gt;
&lt;br /&gt;
Xcodeの立ち上がりは20秒近くだったのが、3〜5秒で立ち上がります。&lt;br /&gt;
Parallels上のWindowsのレジューム時間も、今まで20〜30秒だったのが、5〜8秒。&lt;br /&gt;
Photoshop CS4 Extendedも3秒以内にで立ち上がります。&lt;br /&gt;
とにかくParallelsの動作が圧倒的に高速になりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ベンチ結果は噂ほど大したことは無かったですが、これは環境によると思います。&lt;br /&gt;
ほぼ公称スペックで報告を上げている人も、某価格サイトにはいるので、&lt;br /&gt;
一概にどうとは言えませんが、とりあえず結果を貼っておきます。&lt;br /&gt;
&lt;br /&gt;
測定はXbench&amp;nbsp;Version 1.3にて行いました。&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipR0HF9nTPBUPjqFa_rqObgNFdGQ4yd4_A6_w92ZUkkMluxEoLlDAvUV-KT9MY6wSdaDqWmHsqNRTtg7pfv7UUjdxTrvA4TOMdTHQGJeB2H6kZ8l-qhoF0qNugF9g1-m1x_dZNTSTZGtE/s671/%E6%AE%8B%E3%82%8A148GB.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;MacBook Pro 17-inch Early 2011 SSD換装後ベンチマーク結果&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipR0HF9nTPBUPjqFa_rqObgNFdGQ4yd4_A6_w92ZUkkMluxEoLlDAvUV-KT9MY6wSdaDqWmHsqNRTtg7pfv7UUjdxTrvA4TOMdTHQGJeB2H6kZ8l-qhoF0qNugF9g1-m1x_dZNTSTZGtE/s671/%E6%AE%8B%E3%82%8A148GB.png&quot; height=&quot;356&quot; title=&quot;MacBook Pro 17-inch Early 2011 SSD換装後ベンチマーク結果&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;MacBook Pro 17-inch Early 2011 SSD換装後のベンチマーク結果&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
公称スペックは流石に出なかったものの、シーケンシャルReadが異常に高速。&lt;br /&gt;
&lt;br /&gt;
このMBPとはまだ長い付き合いになりそうです。&lt;br /&gt;
そんでもって、たまには気分転換にMBA持ち出して、&lt;br /&gt;
カフェプログラミングを満喫したいところですな。&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/8434616730084252317/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2013/06/macbook-pro-17-inch-early.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/8434616730084252317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/8434616730084252317'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2013/06/macbook-pro-17-inch-early.html' title='MacBook Pro 17inch Early 2011をSSD(6Gbps)に換装'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcMBCBrcBXrCS9l6lLhGzvYIXunvzqWrrLWR_9U9ajVzv3XX0GIbrejXXZ1BbXbHBAz4uxz6B5OHC1ZkYc0aaXbxgA8dbjNcq6QTJ-s8SBFTbAemBo6ugmUWgBB0qDVy0MprY3XYfRLdM/s72-c/image.jpeg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-7078359604107896911</id><published>2012-11-26T19:30:00.000+09:00</published><updated>2016-01-02T01:57:42.072+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><category scheme="http://www.blogger.com/atom/ns#" term="Win32 API"/><category scheme="http://www.blogger.com/atom/ns#" term="ゲーム"/><category scheme="http://www.blogger.com/atom/ns#" term="コマンドプロンプト"/><category scheme="http://www.blogger.com/atom/ns#" term="ソース"/><title type='text'>コマンドプロンプトアプリケーションにおける終了時処理について</title><content type='html'>コマンドプロンプトアプリケーションにおける終了方法は、主に２つあります。&lt;br /&gt;
&lt;br /&gt;
１つは、アプリケーションがプロセスを終え、自ら終了する場合。&lt;br /&gt;
もう一つは、ユーザが窓を閉じたり強制終了した場合です。&lt;br /&gt;
&lt;br /&gt;
前者は普通、しっかり後処理されるプログラムであれば、正常に終了します。&lt;br /&gt;
問題なのは後者です。&lt;br /&gt;
&lt;br /&gt;
プレイヤーが窓を閉じたり強制終了するというのは、割り込み処理であり、&lt;br /&gt;
本筋のプログラム実行中に、強制的に、&lt;br /&gt;
突然発生するものであるという事を念頭に置かなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
具体的な話として、&lt;br /&gt;
最近流行り（？）のオートセーブ機能付きのゲームを実現したいとします。&lt;br /&gt;
ここではゲーム終了時にゲームデータを保存します。&lt;br /&gt;
&lt;br /&gt;
適当ですがこんな感じで書きました。（雰囲気です）
&lt;br /&gt;
&lt;pre&gt;=============================================
int main(int argc, char* argv[])
{
  int ret = 0;

  &lt;span style=&quot;color: #38761d;&quot;&gt;// 初期化処理&lt;/span&gt;
  if(!GameInit()) {
    &lt;span style=&quot;color: #38761d;&quot;&gt;/* 何らかのエラー処理 */&lt;/span&gt;
    ret = -1;
  } else {
    &lt;span style=&quot;color: #38761d;&quot;&gt;// 実行処理（ゲームループ）&lt;/span&gt;
    if(!GameRunLoop()) {
      &lt;span style=&quot;color: #38761d;&quot;&gt;/* 実行時エラー */&lt;/span&gt;
      ret = -2;
    } else { 
      &lt;span style=&quot;color: #38761d;&quot;&gt;// データ保存処理&lt;/span&gt;
      GameSave();
    }
    &lt;span style=&quot;color: #38761d;&quot;&gt;// 終了時処理&lt;/span&gt;
    GameEnd();
  }

  return ret;
}
=============================================&lt;/pre&gt;
ゲームループを抜けると、&lt;br /&gt;
実行中に異常検知さえなければ必ずデータ保存処理が実行されるため、&lt;br /&gt;
終了時にはオートセーブされるといった具合の作りです。&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;このソースだけ見ても特に大きな問題はない&lt;/span&gt;と思います。&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;問題は、ゲームループ中に窓を閉じられた場合&lt;/span&gt;です。&lt;br /&gt;
というよりこの作りからして、&lt;br /&gt;
初期化処理、保存処理、終了時処理は一瞬で終わるとした場合、&lt;br /&gt;
プレイヤーが窓を閉じるタイミングは、ほぼ100%ゲームループ中です。&lt;br /&gt;
そこで割り込みが発生するとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
結論から言って上記の場合、以下のような悲惨な流れになります。&lt;br /&gt;
１．GameInit　&amp;lt;= 実施&lt;br /&gt;
２．GameRunLoop　&amp;lt;= 実施中に強制停止&lt;br /&gt;
３．GameSave　&amp;lt;= &lt;span style=&quot;color: #cc0000;&quot;&gt;実施されず（頑張ったゲームデータが死亡）&lt;/span&gt;&lt;br /&gt;
４．GameEnd　&amp;lt;= &lt;span style=&quot;color: #cc0000;&quot;&gt;実施されず（解放漏れ。最悪何かのハンドルを掴んだまま）&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
勿論意図するところとしては、１〜４本来全てを実施させたいのですが、&lt;br /&gt;
コンソールアプリケーションではこういう事が普通に起こります。&lt;br /&gt;
&lt;br /&gt;
基本的にGUIでも同じことは言えますが、&lt;br /&gt;
GUIの場合、そもそもIDEを使用していることがほぼ当たり前で、&lt;br /&gt;
そういったIDEが終了処理を記述すべき場所を最初から提供していたりして、&lt;br /&gt;
注意不足でない限り、間違いは起こらないようになっています。&lt;br /&gt;
&lt;br /&gt;
CUIはそういったものは用意されておらず、&lt;br /&gt;
つまり、最初から自分で意図して処理せねばなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それほど詳細に調べ上げてた訳ではありませんが、&lt;br /&gt;
問題の内容をもう少し掘り下げてみます。&lt;br /&gt;
&lt;br /&gt;
コマンドプロンプト(cmd.exe)に限った話をしますと、&lt;br /&gt;
まず、「&lt;span style=&quot;color: #cc0000;&quot;&gt;閉じるボタン&lt;/span&gt;」ですが、&lt;br /&gt;
これは&lt;span style=&quot;color: #cc0000;&quot;&gt;全てのスレッドを強制的に停止&lt;/span&gt;する悪魔のようなボタンです。&lt;br /&gt;
このボタンが押されると、割り込み要求を掛け、&lt;br /&gt;
その時点でプログラムはメインスレッドを停止しています。&lt;br /&gt;
割り込みスレッドをにて何らかの処理を挟み込まない限りなにも処理できません。&lt;br /&gt;
&lt;br /&gt;
じゃあその割り込みスレッドに終了処理を挟み込めばいいと思うのが普通ですが、&lt;br /&gt;
しかし、簡単にはいきません。&lt;br /&gt;
それは、もうひとつの終了方法があるためです。&lt;br /&gt;
&lt;br /&gt;
そのもうひとつの終了方法が「&lt;span style=&quot;color: #cc0000;&quot;&gt;強制終了&lt;/span&gt;」です。&lt;br /&gt;
Ctrl + Alt + Delでタスクマネージャを起動してから良くやるアレですね。&lt;br /&gt;
強制終了を行うと、実は&lt;span style=&quot;color: #cc0000;&quot;&gt;閉じるボタンとは違う動き&lt;/span&gt;をします。&lt;br /&gt;
そこが大きな問題になります。&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;強制終了ではメインスレッドに対して、終了要求をかけているだけ&lt;/span&gt;です。&lt;br /&gt;
そこから一定の時間が経ってプログラムが自主的に終了しない場合、&lt;br /&gt;
ユーザに終了確認を取ります。ダイアログのアレです。&lt;br /&gt;
そこで&lt;span style=&quot;color: #cc0000;&quot;&gt;ユーザーが許可して、初めて全スレッドを停止&lt;/span&gt;します。&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;強制終了は閉じるボタンとは違い&lt;/span&gt;、&lt;br /&gt;
タスクマネージャから強制終了をかけた瞬間に割り込み要求が発生します。&lt;br /&gt;
しかも、メインスレッドは割り込まれているだけで、停止はしていません。&lt;br /&gt;
そこが閉じるボタンとは全く違っていて、&lt;br /&gt;
つまり、割り込みスレッドが発生した後、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;メインスレッドに割り込んだ位置へとプログラムカウンタを復帰し、&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;出来る限り処理を続行しようと努めます&lt;/span&gt;。&lt;br /&gt;
&lt;br /&gt;
その後問題なくプログラムが動き、ユーザーが強制終了を承認しない限り、&lt;br /&gt;
閉じるボタンのように本当に途中で強制終了することはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
正しい終了時処理前提として、システムの割り込みスレッドを捕捉し、&lt;br /&gt;
そこへユーザー処理を挟みこむ必要があるというのは確かですが、&lt;br /&gt;
以上のような「閉じるボタン」と「強制終了」の違いを理解していなければなりません&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
前置きが長くなりましたが、&lt;br /&gt;
この割り込みスレッドの中でユーザ定義の処理を挟み込むには、&lt;br /&gt;
以下のようにハンドラ関数をWindowsに事前通知しておく必要があります。
&lt;br /&gt;
&lt;pre&gt;=============================================
&lt;span style=&quot;color: #cc0000;&quot;&gt;#include &lt;/span&gt;&lt;windows .h=&quot;.h&quot;&gt;&lt;span style=&quot;color: #cc0000;&quot;&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;

&lt;span style=&quot;color: #38761d;&quot;&gt;// 割り込みによるゲーム終了要求フラグ&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;static bool g_InterruptEndReq = false; &lt;/span&gt;

int main(int argc, char* argv[])
{
  int ret = 0;

  &lt;span style=&quot;color: #38761d;&quot;&gt;// ハンドラ関数を登録&lt;/span&gt;
  &lt;span style=&quot;color: #cc0000;&quot;&gt;SetConsoleCtrlHandler(HandlerRoutine, TRUE);&lt;/span&gt;

  &lt;span style=&quot;color: #38761d;&quot;&gt;// 初期化処理&lt;/span&gt;
  if(!GameInit()) {
    &lt;span style=&quot;color: #38761d;&quot;&gt;/* 何らかのエラー処理 */&lt;/span&gt;
    ret = -1;
  } else {
    &lt;span style=&quot;color: #38761d;&quot;&gt;// 実行処理（ゲームループ）
    // （内部ループ条件でg_InterruptEndReq == false判定）&lt;/span&gt;
    if(!GameRunLoop()) {
      &lt;span style=&quot;color: #38761d;&quot;&gt;/* 実行時エラー */&lt;/span&gt;
      ret = -2;
    } else { 
      &lt;span style=&quot;color: #38761d;&quot;&gt;// データ保存処理&lt;/span&gt;
      GameSave();
    }
    &lt;span style=&quot;color: #38761d;&quot;&gt;// 終了時処理&lt;/span&gt;
    GameEnd();
  }

  return ret;
}

&lt;span style=&quot;color: #38761d;&quot;&gt;// ハンドラ関数&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
  BOOL ret = FASLE;&lt;/span&gt;

&lt;span style=&quot;color: #38761d;&quot;&gt;  // ウィンドウの終了イベント検出時
  // ※「閉じるボタン」でも、「強制終了」でも同じフラグ&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;  if(dwCtrlType == CTRL_CLOSE_EVENT) {
    &lt;span style=&quot;color: #38761d;&quot;&gt;// 割り込みによるゲーム終了フラグを立てる&lt;/span&gt;
    g_InterruptEndReq = true;
    ret = TRUE; &lt;span style=&quot;color: #38761d;&quot;&gt;// ハンドラ関数をの連続呼び出しを終了する&lt;/span&gt;
  }
  return ret;
}&lt;/span&gt;
=============================================&lt;/windows&gt;&lt;/pre&gt;
あくまで雰囲気ソースですが、&lt;br /&gt;
このようにすると、Windowsはコマンドプロンプトを閉じようとした場合、&lt;br /&gt;
ハンドラ関数へ特定のイベント処理をコールバックします。&lt;br /&gt;
そこで&lt;span style=&quot;color: #cc0000;&quot;&gt;終了要求のフラグを設定&lt;/span&gt;し、&lt;br /&gt;
ゲームを終了しなければならないことを、ゲームループに通知します。&lt;br /&gt;
&lt;br /&gt;
察しのよい方はお気づきかもしれませんが、&lt;br /&gt;
先ほどまでの説明の通り行くと、&lt;br /&gt;
このプログラムでは「閉じるボタン」を押された際には終了処理が発生しません。&lt;br /&gt;
そのままプログラムは落ちていしまいます。&lt;br /&gt;
なぜなら「閉じるボタン」からのはハンドラ関数終了時には、&lt;br /&gt;
メインスレッドが死んでおり、戻る場所がないからです。&lt;br /&gt;
&lt;br /&gt;
しかし、こうしなければならない理由があります。&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;「強制終了」の場合&lt;/span&gt;、ハンドラ関数が呼び出された時点では、&lt;br /&gt;
メインスレッドの終了が確定していないため、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;ハンドラ関数終了後、割り込みが発生したプログラムカウンタ位置に戻ります&lt;/span&gt;。&lt;br /&gt;
&lt;br /&gt;
つまりどういう事かというと、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;ハンドラ関数で直接終了処理を行ってしまった場合&lt;/span&gt;、&lt;br /&gt;
その後のメインスレッドの処理では当然復帰した位置から処理を継続しようとするため&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;終了処理にて破壊されたアドレスやら変数やらを使用することになってしまう&lt;/span&gt;のです。&lt;br /&gt;
&lt;br /&gt;
ですから、コマンドプロンプトのゲームに関して言うなら、&lt;br /&gt;
ハンドラ関数で投げて良いのは終了要求のみだということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
また、上記ソースのコメントにもあるように、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;ハンドラ関数では「閉じるボタン」か「強制終了」かを区別せず、&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;両方ともウィンドウを閉じるというイベントとして通知されてきます&lt;/span&gt;。&lt;br /&gt;
そのために、ウィンドウの終了方法についての判定は出来ません。&lt;br /&gt;
&lt;br /&gt;
ですので、ハンドラ関数で終了処理をしてしまうと、&lt;br /&gt;
「閉じるボタン」は良いかもしれませんが、&lt;br /&gt;
「強制終了」時は、ほぼ確実にメモリアクセス違反を起こします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では「閉じるボタン」の処置はどうするか？&lt;br /&gt;
&lt;br /&gt;
たどり着いた答えとしては、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;閉じるボタンを無効にする意外に安全な道は無い&lt;/span&gt;ということです。&lt;br /&gt;
&lt;br /&gt;
あくまでここでつくろうとしているのはゲームですから、&lt;br /&gt;
幸い、ゲーム内メニューから終了することや、&lt;br /&gt;
ESCキーで終了するような動作はおおよそ一般的に考えて良いと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
そういうわけで、
&lt;br /&gt;
&lt;pre&gt;=============================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// 閉じるボタンを無効化&lt;/span&gt;
HMENU hmenu = GetSystemMenu(&lt;span style=&quot;color: #cc0000;&quot;&gt;hConsole&lt;/span&gt;, FALSE);
RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
=============================================&lt;/pre&gt;
として、メニューから閉じるボタンを破棄します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #999999;&quot;&gt;(2016/01/02 コメントを頂き訂正)&lt;/span&gt;&lt;br /&gt;
なお、コマンドプロンプトウィンドウのハンドル(上記&lt;span style=&quot;color: #cc0000;&quot;&gt;hConsole&lt;/span&gt;)を得る為&lt;strike&gt;の&lt;/strike&gt;&lt;br /&gt;
&lt;strike&gt;直接的なAPIは存在しませんので、以下のように取得します。
&lt;/strike&gt;&lt;br /&gt;
以下のAPIを呼び出します。&lt;br /&gt;
&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;=============================================&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;HWND APIENTRY GetConsoleWindow(VOID)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;=============================================&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
古い方法では、以下のような関数を定義・利用することで取得可能です。&lt;br /&gt;
（MS公式の資料に基づく取得方法なので、&lt;br /&gt;
　恐らくは上記のAPIも同様の動きかと思います。）&lt;br /&gt;
&lt;pre&gt;=============================================
HWND GetConsoleWindowHandle()
{
  HWND hwnd;
  char newTitle[1024]; &lt;span style=&quot;color: #38761d;&quot;&gt;// ハンドル取得用ウィンドウタイトル&lt;/span&gt;
  char oldTitle[1024]; &lt;span style=&quot;color: #38761d;&quot;&gt;// オリジナルウィンドウタイトル&lt;/span&gt;

  &lt;span style=&quot;color: #38761d;&quot;&gt;// 現在のウィンドウタイトルを取得&lt;/span&gt;
  GetConsoleTitle(oldTitle, sizeof oldTitle);

  &lt;span style=&quot;color: #38761d;&quot;&gt;// ユニークなタイトルに変更し、ウィンドウハンドルを特定&lt;/span&gt;
  sprintf(newTitle, &quot;%d/%d\0&quot;, GetTickCount(), GetCurrentProcessId());
  SetConsoleTitle(newTitle);
  Sleep(40); &lt;span style=&quot;color: #38761d;&quot;&gt;// 誤作動防止に必要&lt;/span&gt;
  hwnd = FindWindow(NULL, newTitle);

  &lt;span style=&quot;color: #38761d;&quot;&gt;// タイトルを戻す&lt;/span&gt;
  SetConsoleTitle(oldTitle);

  return hwnd;
}
=============================================&lt;/pre&gt;
&lt;br /&gt;
これをアプリケーションの初期化時に組み込むことで、&lt;br /&gt;
閉じるボタンは無効となります。 &lt;br /&gt;
つまりはハンドラ関数は強制終了時にのみ対応すれば良く、&lt;br /&gt;
閉じるボタンとの動作の違いに悩まされることは無くなります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
長くなりましたが、以上の仕組みによって、&lt;br /&gt;
コマンドプロンプトのゲームの終了時処理を※正しく動作させることが出来ます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
（※ただし、FPSを採用していない（キー入力待ちが発生する）ゲームでは、&lt;br /&gt;
　キー入力待ちが終わらない限り、この仕組みでは、&lt;br /&gt;
　必ずしもゲームを即時、正常終了させることは出来ません。&lt;br /&gt;
　これは当然のことで、キー入力待ちの処理を標準関数やAPI側で処理すると、&lt;br /&gt;
　自分では終了タイミングを制御できないからです。&lt;br /&gt;
　そこで、コンソールウィンドウをアクティブにして、&lt;br /&gt;
　そこへ無理矢理SendInputなどをしてみましたが動作しませんでした。&lt;br /&gt;
　これについては暇があればもう少し調査したいですが、&lt;br /&gt;
　FPS制御を導入すれば、必然的にハンドラ関数で出した終了要求が&lt;br /&gt;
　ゲームループで検知されて、終了処理が走るため、&lt;br /&gt;
　簡単に解決してしまう話なので特に対策不要と考えています。） </content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/7078359604107896911/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/11/blog-post_26.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/7078359604107896911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/7078359604107896911'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/11/blog-post_26.html' title='コマンドプロンプトアプリケーションにおける終了時処理について'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-6201788715843558924</id><published>2012-11-25T02:23:00.000+09:00</published><updated>2012-11-25T11:18:21.448+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C"/><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><category scheme="http://www.blogger.com/atom/ns#" term="Win32 API"/><category scheme="http://www.blogger.com/atom/ns#" term="ゲーム"/><category scheme="http://www.blogger.com/atom/ns#" term="コマンドプロンプト"/><category scheme="http://www.blogger.com/atom/ns#" term="ソース"/><title type='text'>コンソール(コマンドプロンプト)でダブルバッファリング</title><content type='html'>&lt;span class=&quot;Apple-style-span&quot; style=&quot;-webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); -webkit-tap-highlight-color: rgba(26, 26, 26, 0.296875); font-family: Helvetica; font-size: 16px;&quot;&gt;&lt;br /&gt;
ゲームにおける画面更新で使われるテクニックとして、&lt;br /&gt;
ダブルバッファリングは余りにも有名ですが、&lt;br /&gt;
それはそもそも窓があって、画像があって、その上で語られることだったりします。&lt;br /&gt;
&lt;br /&gt;
ところで、&lt;br /&gt;
コンソールゲームというのは、実験や勉強に向いています。&lt;br /&gt;
GUIであるがゆえに起こる、デザインやらの細かな（ゲームプログラミング以外の）話を余り考える必要はなく、&lt;br /&gt;
本来したいことに集中できるからで、特にGUIを必要としないアルゴリズムの検討、検証などに便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ただ、少し突っ込んでリアルタイムなゲームをつくろうとか、&lt;br /&gt;
そういう事をやろうとすると、最初に必ずげんなりする現象に見舞われます。&lt;br /&gt;
&lt;br /&gt;
つまり、「画面がチラつく」と。&lt;br /&gt;
&lt;br /&gt;
画面を更新する際、本当に簡単な実装をしようとすると、&lt;br /&gt;
Windowsでは、system(&quot;cls&quot;)として画面をクリアしてから、&lt;br /&gt;
ゲームオブジェクトなんかをprintfとかcoutとかすることになります。&lt;br /&gt;
&lt;br /&gt;
しかし通常、それらは１つのスクリーンバッファ上で行われるため、&lt;br /&gt;
一瞬画面が消えて再描画がされてしまい、&lt;br /&gt;
リアルタイムにしようものなら、チラつきが我慢出来ないほどになったりします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
そんなこんなで今回、&lt;br /&gt;
そういった不満を解決するべく、&lt;br /&gt;
コマンドプロンプトでダブルバッファリングをしようというお話です。&lt;br /&gt;
&lt;br /&gt;
まず前提として、&lt;br /&gt;
ここで紹介するのはあくまでもWindowsのコマンドプロンプトの話で、&lt;br /&gt;
加えてWin32APIを使用します。そのためWindowsのみの話になるので悪しからず。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、&lt;br /&gt;
コマンドプロンプトは一つのプロセスに対し、&lt;br /&gt;
スクリーンバッファを複数もつことが出来ます。&lt;br /&gt;
そしてそれら複数のバッファを、自由なタイミングで切り替えて表示することが出来ます。&lt;br /&gt;
&lt;br /&gt;
具体的に、&lt;br /&gt;
「スクリーンバッファを複数もつ」というのは、
&lt;pre&gt;============================================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// スクリーンバッファを作成&lt;/span&gt;
HANDLE hSrceen = &lt;span style=&quot;color: #cc0000;&quot;&gt;CreateConsoleScreenBuffer&lt;/span&gt;(
    GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL
);
if(hSrceen == INVALID_HANDLE_VALUE) {
 &lt;span style=&quot;color: #38761d;&quot;&gt;/* エラー処理 */&lt;/span&gt;
}
============================================================&lt;/pre&gt;
などとして必要な分だけHANDLEを確保することで実現されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
そうして必要な数のスクリーンバッファを新たに作成し、
&lt;pre&gt;============================================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// 対象のスクリーンバッファをアクティブ化&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;SetConsoleActiveScreenBuffer&lt;/span&gt;(hSrceen);
============================================================&lt;/pre&gt;
として、指定のスクリーンバッファ（描画したいものを反映したバッファ）を&lt;br /&gt;
実際に表示するのスクリーンバッファとして指定します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
その選択されたスクリーンバッファに対して、
&lt;pre&gt;============================================================
const char* str = &quot;hogehoge&quot;;
WORD cell;

&lt;span style=&quot;color: #38761d;&quot;&gt;// スクリーンバッファを指定して文字を書き込む&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;WriteConsole&lt;/span&gt;(hSrceen, str, strlen(str), &amp;amp;cell, NULL);
============================================================&lt;/pre&gt;
として、指定のスクリーンバッファに文字（ゲームオブジェクト）を書き込みます&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CreateConsoleScreenBufferで作成したスクリーンバッファは、&lt;br /&gt;
プログラム終了時などに後処理として、
&lt;pre&gt;============================================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// スクリーンバッファを解放&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;CloseHandle&lt;/span&gt;(hSrceen);
hSrceen = NULL;
============================================================&lt;/pre&gt;
などととしておきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以上に上げたAPIの他にもまだ、ゲームを作る上で必要なAPIがあります。&lt;br /&gt;
例えばタイトルを設定したり、&lt;br /&gt;
カーソルの表示を切り替えたり、&lt;br /&gt;
フォントの色を変えたり　などなど・・・&lt;br /&gt;
&lt;br /&gt;
そういった事に関しては、&lt;br /&gt;
Microsoftの&lt;a href=&quot;http://msdn.microsoft.com/ja-jp/library/cc429123.aspx&quot; target=&quot;_blank&quot;&gt;オンラインMSDNのコンソールAPIページ&lt;/a&gt;が参考になります。&lt;br /&gt;
ここを参考にすれば大抵はなんとかなるかと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここで注意事項ですが、&lt;br /&gt;
Win32 APIであるCreateConsoleScreenBuffer()は、&lt;br /&gt;
作成されるスクリーンバッファのサイズが既にあるウィンドウの複製サイズとなっており、&lt;br /&gt;
コマンドプロンプトのウィンドウの大きさとイコールのサイズです。&lt;br /&gt;
&lt;br /&gt;
一方、
&lt;pre&gt;============================================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// 標準のスクリーンバッファを取得&lt;/span&gt;
HANDLE hConsoleOut = &lt;span style=&quot;color: #cc0000;&quot;&gt;GetStdHandle&lt;/span&gt;(STD_OUTPUT_HANDLE);
if(hConsoleOut == INVALID_HANDLE_VALUE) {
 &lt;span style=&quot;color: #38761d;&quot;&gt;/* エラー処理 */&lt;/span&gt;
}
============================================================&lt;/pre&gt;
として取得できるスクリーンバッファは、&lt;br /&gt;
初期状態では縦のバッファサイズがウィンドウサイズを越えているため、&lt;br /&gt;
スクロールバーが付いています。&lt;br /&gt;
&lt;br /&gt;
よって、GetStdHandle()で取得した標準スクリーンバッファと、&lt;br /&gt;
CreateConsoleScreenBuffer()で作成したもう１つのスクリーンバッファで、&lt;br /&gt;
そのままダブルバッファリングをしようとすると、&lt;br /&gt;
例えばFPS制御しているプログラムでは、&lt;br /&gt;
スクロールバーが付いている画面と、付いていない画面が交互に表示されてしまい、&lt;br /&gt;
目も当てられない事になります。&lt;br /&gt;
&lt;br /&gt;
因みに、GetStdHandle()でハンドルを取得した場合も、&lt;br /&gt;
後処理などでCloseHandle()を呼び出して解放する必要があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先程のバッファサイズの違いの問題を回避するには、&lt;br /&gt;
GetStdHandle()して取得した標準スクリーンバッファのサイズ、&lt;br /&gt;
及びをウィンドウサイズを&lt;br /&gt;
&lt;pre&gt;============================================================
COORD coord = { MAX_WIDTH, MAX_HEIGHT };
SMALL_RECT sr = { 0, 0, (MAX_WIDTH-1), (MAX_HEIGHT-1) };

&lt;span style=&quot;color: #38761d;&quot;&gt;// バッファサイズ変更&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;SetConsoleScreenBufferSize&lt;/span&gt;(hConsoleOut, coord);
&lt;span style=&quot;color: #38761d;&quot;&gt;// ウィンドウサイズ変更&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;SetConsoleWindowInfo&lt;/span&gt;(hConsoleOut, TRUE, &amp;amp;sr); 
============================================================&lt;/pre&gt;
などとするか、&lt;br /&gt;
そもそも、GetStdHandle()して取得した標準スクリーンバッファは使用しないことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上記のサイズ問題については良いとして、&lt;br /&gt;
もうひとつの問題があります。&lt;br /&gt;
&lt;br /&gt;
標準のスクリーンバッファをいじるということは、&lt;br /&gt;
後々復帰処理の為に起動直後のバッファの内容を保持する必要が有るという問題です。&lt;br /&gt;
&lt;br /&gt;
その問題から、私は標準のスクリーンバッファを使用しないことを推奨します。&lt;br /&gt;
&lt;br /&gt;
そもそも、コマンドラインから「C:¥&amp;gt;game.exe」などとされた場合、&lt;br /&gt;
ゲーム中に標準のスクリーンバッファを使用していると、その内容を上書きしてしまいます。&lt;br /&gt;
標準のスクリーンバッファをクリアされるようなことは、&lt;br /&gt;
ユーザ兼プレイヤー側としては意図しない現象なのです。&lt;br /&gt;
&lt;br /&gt;
何らかの作業中に、ちょっと寄り道してゲームを起動したら、ゲーム起動前に作業していた内容が全て消えていた、なんて事になるのですから。&lt;br /&gt;
そんな事はプレイヤーは想定していないというか、させること事自体おかしいのです。&lt;br /&gt;
&lt;br /&gt;
ですから繰り返しますが、&lt;br /&gt;
標準のスクリーンバッファの内容を最初に保持するか、&lt;br /&gt;
または標準のスクリーンバッファには手をつけない作り方をしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、&lt;br /&gt;
ここまでの流れをまとめて、もう少し補足したプログラムとして、&lt;br /&gt;
初期に公開していた「カードチェイン」にダブルバッファリング対応したものをソース付きで公開します。&lt;br /&gt;
バージョン0.8.0から描画周りのベース処理がかなり改善されています。&lt;br /&gt;
ただし、ゲームの内容クラスであるCardChain.cppには一切手を付けていません。&lt;br /&gt;
（FPS対応はする必要がないゲームですので、していません。）&lt;br /&gt;
&lt;br /&gt;
また、ダブルバッファリング（描画周り）以外の部分でも、特記すべき事項が2点あり、&lt;br /&gt;
それも既に適用していますが、そこはまた別の機会に書きたいと思います。&lt;br /&gt;
&lt;br /&gt;
実行ファイルとソースのセットで、&lt;br /&gt;
ソースはVC++ 2010 Expressのプロジェクト付きです。&lt;br /&gt;
&lt;br /&gt;
ゲームルールや操作方法、動作環、ライセンス、免責事項などについては、&lt;br /&gt;
&lt;a href=&quot;http://tama012.blogspot.jp/2012/10/card-chain.html&quot; target=&quot;_blank&quot;&gt;前バージョンのカードチェイン&lt;/a&gt;の説明と同様なので、&lt;br /&gt;
そちらをご参照ください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カードチェイン ver. 0.9.0&lt;br /&gt;
&lt;br /&gt;
▽ Download ▽&lt;br /&gt;
&lt;a href=&quot;https://docs.google.com/open?id=0Bz1zlwZ1RkLWSFdZU3VaVEFiYWc&quot; target=&quot;_blank&quot;&gt;https://docs.google.com/open?id=0Bz1zlwZ1RkLWSFdZU3VaVEFiYWc&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
一括ダウンロード方法が不明な場合は、&lt;a href=&quot;http://tama012.blogspot.jp/2012/10/blog-post_27.html&quot; target=&quot;_blank&quot;&gt;こちら&lt;/a&gt;を御覧ください。
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下、駄文です&lt;br /&gt;
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜&lt;br /&gt;
実はダブルバッファリングをせずとも、「チラつきのない描画」はほぼ可能です。&lt;br /&gt;
ようは、「一度すべて消すからチラつく」ということです。&lt;br /&gt;
必要な部分を毎回上書きするように書き換えるか、&lt;br /&gt;
(※)ゲーム画面全体分の描画すべき情報をあらかじめ集約し、&lt;br /&gt;
それをもって一度だけのループで完成された画面の描画を行えば、&lt;br /&gt;
そもそもダブルバッファリングは不要です。&lt;br /&gt;
（※例えば、シングルバッファだと、&lt;br /&gt;
　フィールドマップを描画したのち、その上にキャラクターを描画しようしても、&lt;br /&gt;
　printfを同じ場所(セル)に2回適用した時点で時間差によるチラツキが発生します。&lt;br /&gt;
　その為、一度メモリ上にバッファを持って、その上でマップとキャラクターを統合すれば、&lt;br /&gt;
　そのバッファの内容を一度で描画する事ができます。&lt;br /&gt;
　応用して、常にゲーム画面全ての内容をそのメモリ上に構築するようにすれば、&lt;br /&gt;
　画面全体を1度のの描画で瞬時に書き換えられるため、チラつきはほぼ起こりません。）&lt;br /&gt;
&lt;br /&gt;
が、それというのはそもそも、&lt;br /&gt;
コンソールゲームに完全に依存してしまう作りであり、&lt;br /&gt;
しかも、(※)そのゲームとは本来関係ない内容を、ゲーム側のソースに埋め込むことになります。&lt;br /&gt;
よって、移植性の乏しい物が出来上がってしまうのです。&lt;br /&gt;
また、一望しただけではよくわからないものになっている可能性もあります。&lt;br /&gt;
（※ただし、前述した描画用のメモリ管理を別機能として提供すればそのような問題は起こりませんが、&lt;br /&gt;
　実際にやろうとすると、カラフルなコンソールゲームである場合に不都合が生まれます。&lt;br /&gt;
　メモリ統合の際に文字毎の背景色を記憶するわけですが、&lt;br /&gt;
　それはマルチバイトのプロジェクトはともかとして、&lt;br /&gt;
　Unicodeプロジェクトを作成する場合、UTF-16』で全角半角の判定をし、&lt;br /&gt;
　その文字が1セル分なのか、2セル分なのかを判定し、背景色を適用しなければなりません。&lt;br /&gt;
　UTF-16では、S-JISやEUC-JPなどと違って、単純に半角と全角を判定できるものではありません。&lt;br /&gt;
　使用される文字が限定すればそういう事も出来ますが、&lt;br /&gt;
　どちらにしても、そういった制御を行うことで、パフォーマンスが落ちることは避けられませんし、&lt;br /&gt;
　非効率であることに変わりはないのです。）&lt;br /&gt;
そういうわけで、自由にバッファの内容を上書きできるダブルバッファリングは、&lt;br /&gt;
コンソールアプリケーションであっても有効なのです。&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/6201788715843558924/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/11/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/6201788715843558924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/6201788715843558924'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/11/blog-post.html' title='コンソール(コマンドプロンプト)でダブルバッファリング'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-3398150542150849611</id><published>2012-10-27T21:37:00.002+09:00</published><updated>2012-10-28T01:28:06.011+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="アルゴリズム"/><category scheme="http://www.blogger.com/atom/ns#" term="ソース"/><category scheme="http://www.blogger.com/atom/ns#" term="テンプレート"/><title type='text'>ビットの位置(≒２の冪指数)を静的算出するtemplateメタプログラム</title><content type='html'>ビットフラグを使用していると、&lt;br /&gt;
たまに「そのフラグが立てているビットの位置」を知りたいというときがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
結論から言って、&lt;br /&gt;
以下のテンプレートクラス(構造体ですが、、)を書きました。&lt;br /&gt;
&lt;pre&gt;==================================
typedef unsigned int U32;

&lt;span style=&quot;color: #38761d;&quot;&gt;// ビット位置の静的算出
// 値Nについて、最大のビット位置を求める
//（例：N:127→7, N:128→8&lt;/span&gt;
template&amp;lt;U32 N&amp;gt; struct BitPos
{
 enum {
  pos = BitPos&amp;lt;N/2&amp;gt;::pos + 1,
 };
};
template&amp;lt;&amp;gt; struct BitPos&amp;lt;1&amp;gt; { enum { pos = 0 }; };  &lt;span style=&quot;color: #38761d;&quot;&gt;// 終了条件1&lt;/span&gt;
template&amp;lt;&amp;gt; struct BitPos&amp;lt;0&amp;gt; { enum { pos = -1 }; }; &lt;span style=&quot;color: #38761d;&quot;&gt;// 終了条件2&lt;/span&gt;
==================================&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
これはテンプレートメタプログラミングと呼ばれる、&lt;br /&gt;
C++のテクニックとしては古いものです。&lt;br /&gt;
&lt;br /&gt;
このテクニックを利用すると、入力値に対しコンパイル時に値が算出されるため、&lt;br /&gt;
実行時の演算コストがなくなります。&lt;br /&gt;
コンパイル時に時間的なコストがあるといえばありますが。&lt;br /&gt;
&lt;br /&gt;
動作的原理については、&lt;a href=&quot;http://ja.wikipedia.org/wiki/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%83%A1%E3%82%BF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&quot; target=&quot;_blank&quot;&gt;Wikipedia&lt;/a&gt;に詳しく書かれています。&lt;br /&gt;
&lt;br /&gt;
このテンプレートは定数posの値を、&lt;br /&gt;
コンパイル時の再帰呼び出しによって決定します。&lt;br /&gt;
&lt;br /&gt;
たとえば以下のように使用します。&lt;br /&gt;
&lt;pre&gt;==================================
static const U32 BIT_FLG = 0x04000000; &lt;span style=&quot;color: #38761d;&quot;&gt;// 例えばこんな定数がある&lt;/span&gt;

std::cout &amp;lt;&amp;lt; BitPos&amp;lt;BIT_FLG&amp;gt;::pos &amp;lt;&amp;lt; std::endl;

&lt;span style=&quot;color: #38761d;&quot;&gt;
// 結果は26となる
// 0x04000000 =&amp;gt; 0000 0100 0000 0000 0000 0000 0000 0000
&lt;/span&gt;
==================================&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;大まかには以上です。 &lt;/pre&gt;
&lt;pre&gt;&lt;/pre&gt;
※　終了条件2について、-1としていますが、&lt;br /&gt;
この辺りは人によって意見が分かれるかもしれません。&lt;br /&gt;
個人的には、ビットフラグに0というのはフラグとして成り立っていないと考え、&lt;br /&gt;
設定値として無効な値であるから-1というエラー値を設定しています。&lt;br /&gt;
これが正しいというには難しいため、好みにより-1でも0でも良いと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜&lt;br /&gt;
以下は説明と見せかけて駄文です。&lt;br /&gt;
興味のある方だけお読みください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、&lt;br /&gt;
&lt;pre&gt;==================================
typedef unsigned short U16;
static const U16 BIT_FLG_A = 0x1000;
static const U16 BIT_FLG_B = 0x2000;
static const U16 BIT_FLG_C = 0x4000;
static const U16 BIT_FLG_D = 0x8000;
==================================
&lt;/pre&gt;
&lt;br /&gt;
という定義があったとして、&lt;br /&gt;
ある変数について、このビットフラグを扱うとき、&lt;br /&gt;
【0x0000】または【0x0001】という結果を、&lt;br /&gt;
演算で求めたい場合があるとします。&lt;br /&gt;
&lt;br /&gt;
そのとき場合のコードはこうなると思います。&lt;br /&gt;
&lt;pre&gt;==================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// 入力値 U16 hoge = 0x2018 から0x2000を得て、&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;// 0x0000 or 0x0001を得る&lt;/span&gt;

U16 ret = 0x0000;
ret = (hoge &amp;amp; BIT_FLG_B) &amp;gt;&amp;gt; &lt;span style=&quot;color: #cc0000;&quot;&gt;13&lt;/span&gt;;  &lt;span style=&quot;color: #38761d;&quot;&gt;// ここにリテラルが発生する&lt;/span&gt;
==================================
&lt;/pre&gt;
&lt;br /&gt;
この例題だと正直、素直にif文でもよいですが、&lt;br /&gt;
ここではそういう話はしません。&lt;br /&gt;
&lt;br /&gt;
コメントに記したように、&lt;br /&gt;
0x0001を得るために13bit右シフトを意味するリテラルを書くわけですが、&lt;br /&gt;
この13というリテラルは気持ち悪いと感じる事もあるでしょう。&lt;br /&gt;
だからこの13に対して BIT_FLG_Bの対となる定数をまた用意したりして、&lt;br /&gt;
&lt;pre&gt;==================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;BIT_FLG_Bでマスクした結果から&lt;span style=&quot;color: #38761d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;// 0x0000 or 0x0001を得るための定数値&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;static const U16 FLG_B_SHIFT_NUM = 13;&lt;/span&gt;


&lt;span style=&quot;color: #38761d;&quot;&gt;// 入力値 U16 hoge = 0x2018&lt;/span&gt;
U16 ret = 0x0000;
ret = (hoge &amp;amp; BIT_FLG_B) &amp;gt;&amp;gt; &lt;span style=&quot;color: #cc0000;&quot;&gt;FLG_B_SHIFT&lt;span style=&quot;color: #cc0000;&quot;&gt;_NUM&lt;/span&gt;&lt;/span&gt;;  &lt;span style=&quot;color: #38761d;&quot;&gt;// 定数に変更&lt;/span&gt;
==================================&lt;/pre&gt;
&lt;br /&gt;
とかやってはみるものの、&lt;br /&gt;
非常に無駄な作業をしている気がしてならなくなってくるわけです。&lt;br /&gt;
&lt;br /&gt;
もう面倒だから13でいいやとか、投げやりにもなりたくなります。&lt;br /&gt;
&lt;br /&gt;
更に、データフォーマットが変わってしまって、&lt;br /&gt;
型がU16からU8（unsigned charとします）に変えなければならない時、 &lt;br /&gt;
&lt;br /&gt;
この【FLG_B_SHIFT】の型、定数値も変えてやらなければならないという事態になります。&lt;br /&gt;
&lt;pre&gt;==================================
static const &lt;span style=&quot;color: #cc0000;&quot;&gt;U8&lt;/span&gt; BIT_FLG_A = &lt;span style=&quot;color: #cc0000;&quot;&gt;0x10&lt;/span&gt;;
static const &lt;span style=&quot;color: #cc0000;&quot;&gt;U8&lt;/span&gt; BIT_FLG_B = &lt;span style=&quot;color: #cc0000;&quot;&gt;0x20&lt;/span&gt;;
static const &lt;span style=&quot;color: #cc0000;&quot;&gt;U8&lt;/span&gt; BIT_FLG_C = &lt;span style=&quot;color: #cc0000;&quot;&gt;0x40&lt;/span&gt;;
static const &lt;span style=&quot;color: #cc0000;&quot;&gt;U8&lt;/span&gt; BIT_FLG_D = &lt;span style=&quot;color: #cc0000;&quot;&gt;0x80&lt;/span&gt;;

&lt;span style=&quot;color: #38761d;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;BIT_FLG_Bでマスクした結果から&lt;span style=&quot;color: #38761d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color: #38761d;&quot;&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;// 0x00 or 0x01を得るための定数値&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;static const U8 FLG_B_SHIFT&lt;/span&gt;&lt;span style=&quot;color: #cc0000;&quot;&gt;&lt;span style=&quot;color: #cc0000;&quot;&gt;_NUM&lt;/span&gt; = 5;&lt;/span&gt;

&lt;span style=&quot;color: #38761d;&quot;&gt;// 入力値 U8 hoge = 0x24&lt;/span&gt;
U8 ret = 0x00;
ret = (hoge &amp;amp; BIT_FLG_B) &amp;gt;&amp;gt; &lt;span style=&quot;color: #cc0000;&quot;&gt;FLG_B_SHIFT&lt;/span&gt;&lt;span style=&quot;color: #cc0000;&quot;&gt;_NUM&lt;/span&gt;;
==================================&lt;/pre&gt;
↑こんなふうに。
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ではもっと、効率的で意味を可視化できる方法がないでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここで、0x20と5との関係性を考えたとき、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;2^5 = 32 (=0x20)&lt;/span&gt;であるということがあります。&lt;br /&gt;
これは逆に32を2で5回割れば1となるというとです。&lt;br /&gt;
&lt;br /&gt;
と言うことで、&lt;br /&gt;
冒頭のtemplateでは、1 &amp;lt; Nの関係が成り立つ間、&lt;br /&gt;
N÷2を再帰的に繰り返せばいいじゃないという発想のもと、ビット位置を算出しています。&lt;br /&gt;
&lt;br /&gt;
前述のソースに適用すると、&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;==================================
static const U8 BIT_FLG_A = 0x10;
static const U8 BIT_FLG_B = 0x20;
static const U8 BIT_FLG_C = 0x40;
static const U8 BIT_FLG_D = 0x80;

&lt;span style=&quot;color: #38761d;&quot;&gt;// 入力値 U8 hoge = 0x24&lt;/span&gt;
U8 ret = 0x00;
ret = (hoge &amp;amp; BIT_FLG_B) &amp;gt;&amp;gt; &lt;span style=&quot;color: #cc0000;&quot;&gt;BitPos&amp;lt;BIT_FLG_B&amp;gt;::pos&lt;/span&gt;;
==================================&lt;/pre&gt;
となり、BIT_FLG_xがどんな値であるかを意識する必要がなくなります。&lt;br /&gt;
&lt;br /&gt;
ただし、一つ難点があるといえば、&lt;br /&gt;
BitPos&amp;lt;xxx&amp;gt;::posとかいってますが、一体どこのposなのか判らないということです。&lt;br /&gt;
&lt;br /&gt;
例えば&lt;span style=&quot;color: #cc0000;&quot;&gt;0x24&lt;/span&gt;(0010 0100)という２つのフラグがある場合、&lt;br /&gt;
これに対してはどこのbit位置なのか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
そこで、冒頭のテンプレートを &lt;br /&gt;
以下のように変更することで、より意味を明確にしました。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;==================================
&lt;span style=&quot;color: #38761d;&quot;&gt;// ビット位置の静的算出
// 値Nについて、最大のビット位置と最小のビット位置を求める
//（例：124→most:7, least:2、 128→most:8, least:8&lt;/span&gt;
template&amp;lt;U32 N&amp;gt; struct BitPos
{
 enum {
  &lt;span style=&quot;color: #cc0000;&quot;&gt;most&lt;/span&gt; = BitPos&amp;lt;N/2&amp;gt;::&lt;span style=&quot;color: #cc0000;&quot;&gt;most&lt;/span&gt; + 1,    &lt;span style=&quot;color: #38761d;&quot;&gt;// 最大位置&lt;/span&gt;
  &lt;span style=&quot;color: #cc0000;&quot;&gt;least = ((N &amp;amp; 1) == 0) ? BitPos&amp;lt;N / 2&amp;gt;::least + 1 : 0&lt;/span&gt; &lt;span style=&quot;color: #38761d;&quot;&gt;// 最小位置&lt;/span&gt;
 };
};
template&amp;lt;&amp;gt; struct BitPos&amp;lt;1&amp;gt; { enum { most = 0&lt;span style=&quot;color: #cc0000;&quot;&gt;, least = 0&lt;/span&gt; }; };
template&amp;lt;&amp;gt; struct BitPos&amp;lt;0&amp;gt; { enum { most = -1&lt;span style=&quot;color: #cc0000;&quot;&gt;, least = -1&lt;/span&gt; }; };
==================================&lt;/pre&gt;
leastはNのLSBが0である間だけbit位置をカウントします。&lt;br /&gt;
LSBが1になれば、つまり最初の最小のビット位置を発見したということなので、&lt;br /&gt;
再帰呼び出しを終了します。&lt;br /&gt;
また、そもそも最初の入力値Nが0というのはビットフラグとして成り立っていないため、&lt;br /&gt;
強制的にカウントを-1として終了します。&lt;br /&gt;
&lt;br /&gt;
N=1のときは、LSBが立っていることが明らかであるため、&lt;br /&gt;
結果を0ビット目とします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以上、&lt;br /&gt;
長々とお付き合い頂き、ありがとうございました。&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/3398150542150849611/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/10/template.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/3398150542150849611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/3398150542150849611'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/10/template.html' title='ビットの位置(≒２の冪指数)を静的算出するtemplateメタプログラム'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-3535944956238982993</id><published>2012-10-27T15:17:00.000+09:00</published><updated>2012-10-27T15:42:36.994+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="お知らせ"/><category scheme="http://www.blogger.com/atom/ns#" term="紹介"/><title type='text'>ダウンロードリンクの修正について</title><content type='html'>コマンドプロンプトゲーム「CardChain」のダウンロード先について、&lt;br /&gt;
&amp;nbsp;ダウンロードに承認が必要な状態になっていたようなので、&lt;br /&gt;
&amp;nbsp;承認が不要であるよう修正しました。&lt;br /&gt;
&lt;br /&gt;
ダウンロード手順は難しくはないですが、&lt;br /&gt;
少し迷うこともあるかと思うので記載しておきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;ダウンロードリンクをクリックすると、以下のようにファイル一覧が表示されます
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLbIgzIISq8R41Wi0FzETtMMxh3u50tNdvtUTkBYNhslESIfiAW7XBO7RsMlPlkp1sTl-df6DPEs3kKkEl-p8V8YK4lzCNRNxAxDMh8jEUUJe2Rr4mBonGj01Mk5hYqS5CNy72Luu7qxQ/s1600/%25E3%2582%25BF%25E3%2582%2599%25E3%2582%25A6%25E3%2583%25B3%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%2588%25E3%2582%2599.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLbIgzIISq8R41Wi0FzETtMMxh3u50tNdvtUTkBYNhslESIfiAW7XBO7RsMlPlkp1sTl-df6DPEs3kKkEl-p8V8YK4lzCNRNxAxDMh8jEUUJe2Rr4mBonGj01Mk5hYqS5CNy72Luu7qxQ/s320/%25E3%2582%25BF%25E3%2582%2599%25E3%2582%25A6%25E3%2583%25B3%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%2588%25E3%2582%2599.png&quot; width=&quot;251&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
上部メニューから、「ファイル」を選択します。&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEattedeR44PBZtmeUAs6jbLCrack6_o3Tl8fdWEXUema7ONqTbdZYuPHVWmD0-0TX2YS652qh6HnzgSLjCmTDxm_uOinTI79XrywzYo7brGE4-ClcMuZUCS3KDbrtWgDIuhjU4qFvYjE/s1600/%E3%82%BF%E3%82%99%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%88%E3%82%992.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEattedeR44PBZtmeUAs6jbLCrack6_o3Tl8fdWEXUema7ONqTbdZYuPHVWmD0-0TX2YS652qh6HnzgSLjCmTDxm_uOinTI79XrywzYo7brGE4-ClcMuZUCS3KDbrtWgDIuhjU4qFvYjE/s320/%E3%82%BF%E3%82%99%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%88%E3%82%992.png&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
ファイルから「ダウンロード」を選択します。&lt;br /&gt;
&lt;br /&gt;
以上です。&lt;br /&gt;
今後のダウンロード先も、同じようにしたいと思います。&lt;br /&gt;
&lt;br /&gt;
また、リンク切れなどの問題や、&lt;br /&gt;
やこうした方がもっと良いというご意見があればお知らせください。 &lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/3535944956238982993/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post_27.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/3535944956238982993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/3535944956238982993'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post_27.html' title='ダウンロードリンクの修正について'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLbIgzIISq8R41Wi0FzETtMMxh3u50tNdvtUTkBYNhslESIfiAW7XBO7RsMlPlkp1sTl-df6DPEs3kKkEl-p8V8YK4lzCNRNxAxDMh8jEUUJe2Rr4mBonGj01Mk5hYqS5CNy72Luu7qxQ/s72-c/%25E3%2582%25BF%25E3%2582%2599%25E3%2582%25A6%25E3%2583%25B3%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%2588%25E3%2582%2599.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-7647083945674958390</id><published>2012-10-13T01:40:00.002+09:00</published><updated>2012-10-27T21:39:17.590+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="アルゴリズム"/><category scheme="http://www.blogger.com/atom/ns#" term="ソース"/><category scheme="http://www.blogger.com/atom/ns#" term="テンプレート"/><category scheme="http://www.blogger.com/atom/ns#" term="最適化"/><title type='text'>ビット逆転アルゴリズムのテンプレート化と最適化について</title><content type='html'>ビット逆転のアルゴリズムとして、効率的なコードとして、&lt;br /&gt;
以下のようなものがよく見られるようです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
unsigned int v;
v = ((v &amp;amp; 0xaaaaaaaa) &amp;gt;&amp;gt; 1) | ((v &amp;amp; 0x55555555) &amp;lt;&amp;lt; 1);
v = ((v &amp;amp; 0xcccccccc) &amp;gt;&amp;gt; 2) | ((v &amp;amp; 0x33333333) &amp;lt;&amp;lt; 2);
v = ((v &amp;amp; 0xf0f0f0f0) &amp;gt;&amp;gt; 4) | ((v &amp;amp; 0x0f0f0f0f) &amp;lt;&amp;lt; 4);
v = ((v &amp;amp; 0xff00ff00) &amp;gt;&amp;gt; 8) | ((v &amp;amp; 0x00ff00ff) &amp;lt;&amp;lt; 8);
v = (v &amp;gt;&amp;gt; 16) | (v &amp;lt;&amp;lt; 16);
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
1bit単位、2bit単位、4bit単位、8bit単位で交換し、最後に16bit単位で交換した結果、ビットの並びが上下逆となります。&lt;br /&gt;
簡単に8bitでトレースしてみると、、&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
v == 01111001
　　↓　　左側　((01111001 &amp;amp; 10101010) &amp;gt;&amp;gt; 1)&amp;nbsp; =&amp;gt; 00010100
　　↓　　右側　((01111001 &amp;amp; 01010101) &amp;lt;&amp;lt; 1)&amp;nbsp; =&amp;gt; 10100010
　　↓　　00010100 | 10100010
v == 10110110
　　↓　　左側　((10110110 &amp;amp; 11001100) &amp;gt;&amp;gt; 2)&amp;nbsp; =&amp;gt; 00100001
　　↓　　右側　((10110110 &amp;amp; 00110011) &amp;lt;&amp;lt; 2)&amp;nbsp; =&amp;gt; 11001000
　　↓　　00100001 | 11001000
v == 11101001
　　↓　　左側　(11101001 &amp;gt;&amp;gt; 4)&amp;nbsp; =&amp;gt; 00001110
　　↓　　右側　(11101001 &amp;lt;&amp;lt; 4)&amp;nbsp; =&amp;gt; 10010000
　　↓　　00001110 | 10010000
v == 10011110
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
という感じです。&lt;br /&gt;
書きだしてみると少し長くなりましたが、 &lt;br /&gt;
頭で考えたほうがかえって分かりやすいアルゴリズムだと思います。&lt;br /&gt;
上記のアルゴリズムを見つけたときは感心しました。&lt;br /&gt;
&lt;br /&gt;
因みに最初に自作したのは以下のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
// 自作初期型
T val = 0x89ABCDEF;

const T size = sizeof(T) * 8 - 1;
T tmp = 0;
for(T i = 0; i &amp;lt;= size; i++) {
 tmp |= (val &amp;amp; (1 &amp;lt;&amp;lt; size)) &amp;gt;&amp;gt; (size - i);
 val &amp;lt;&amp;lt;= 1;
}
return tmp;
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
常にvalのMSBを取り出し、&lt;br /&gt;
tmpのLSBからMSBへ順番に型のサイズ分だけ繰り返して設定する事で逆転させています。&lt;br /&gt;
sizeofによって可変サイズに対応できるため、template可能です。 &lt;br /&gt;
この場合のsizeofは、通常コンパイル時には最適化によって定数へと置き換えられ、&lt;br /&gt;
例えばunsigned short(以下 U16)の時、実質的なコードは、&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
// コンパイラ最適化後イメージ
U16 val = 0xABCD;
&lt;span style=&quot;color: #cc0000;&quot;&gt;// const T size = sizeof(T) * 8 - 1; &amp;lt;=削除される&lt;/span&gt;
U16 tmp = 0;
for(U16 i = 0; i &amp;lt;= &lt;span style=&quot;color: #cc0000;&quot;&gt;15&lt;/span&gt;; i++) {
 tmp |= (val &amp;amp; &lt;span style=&quot;color: #cc0000;&quot;&gt;0x8000&lt;/span&gt;) &amp;gt;&amp;gt; (&lt;span style=&quot;color: #cc0000;&quot;&gt;15&lt;/span&gt; - i);
 val &amp;lt;&amp;lt;= 1;
}
return tmp;
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
と、言った感じになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかしながら、 &lt;br /&gt;
汎用的ではあるものの、冒頭のアルゴリズムを目にして、&lt;br /&gt;
うがががが(；´Д｀)。。&lt;br /&gt;
となったため、&lt;br /&gt;
なんとか冒頭のアルゴリズムをtemplateに適用したいと考えました。&lt;br /&gt;
&lt;br /&gt;
・・・&lt;br /&gt;
で、出来たのは以下のコード。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
template&amp;lt;typename t&amp;gt; static T reverseBits(T v) {
 assert(sizeof T &amp;lt;= 4);
 switch(sizeof T) {
  case 4: v = (v &amp;gt;&amp;gt; 16) | (v &amp;lt;&amp;lt; 16);
  case 2: v = ((v &amp;amp; 0xff00ff00) &amp;gt;&amp;gt; 8) | ((v &amp;amp; 0x00ff00ff) &amp;lt;&amp;lt; 8);
  case 1: v = ((v &amp;amp; 0xf0f0f0f0) &amp;gt;&amp;gt; 4) | ((v &amp;amp; 0x0f0f0f0f) &amp;lt;&amp;lt; 4);
   v = ((v &amp;amp; 0xcccccccc) &amp;gt;&amp;gt; 2) | ((v &amp;amp; 0x33333333) &amp;lt;&amp;lt; 2);
   v = ((v &amp;amp; 0xaaaaaaaa) &amp;gt;&amp;gt; 1) | ((v &amp;amp; 0x55555555) &amp;lt;&amp;lt; 1);
 }
 return v;
}
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
switch文が入りました。&lt;br /&gt;
&lt;br /&gt;
冒頭のアルゴリズムの特性として、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;各行の交換式は干渉していない&lt;/span&gt;ということが挙げられます。 &lt;br /&gt;
なので、&lt;span style=&quot;color: #cc0000;&quot;&gt;順番がどうであれ、最後には交換が出来る&lt;/span&gt;はずです。&lt;br /&gt;
&lt;br /&gt;
ということなので、&lt;br /&gt;
&lt;br /&gt;
交換順を逆に定義した上で、&lt;br /&gt;
switch文を全て通り抜けるようにしてやることで、必要な分だけ演算を実施させます。 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
が、この&lt;span style=&quot;color: #cc0000;&quot;&gt;switch文は入っているように見えるだけで、実際には入らない&lt;/span&gt;です。&lt;br /&gt;
&lt;br /&gt;
これは関数テンプレートであり、渡される型はコンパイル時には決まっており、&lt;br /&gt;
また、switchの対象が型サイズであるために、これもコンパイル時に解決され、&lt;br /&gt;
つまり最初からジャンプ先が決定しているのでswitchする必要がなく、&lt;br /&gt;
&lt;span style=&quot;color: #cc0000;&quot;&gt;コンパイラの最適化により、型サイズによって直接的に必要な交換式のみを実行するコードが生成&lt;/span&gt;されます。&lt;br /&gt;
&lt;br /&gt;
また、別の問題として考えられるのは、&lt;br /&gt;
上記の交換式はすべて32bitのリテラルが組み込まれていることです。&lt;br /&gt;
『v = ((v &amp;amp; &lt;span style=&quot;color: #cc0000;&quot;&gt;0xaaaaaaaa&lt;/span&gt;) &amp;gt;&amp;gt; 1) | ((v &amp;amp; &lt;span style=&quot;color: #cc0000;&quot;&gt;0x55555555&lt;/span&gt;) &amp;lt;&amp;lt; 1);』 &lt;br /&gt;
これはキャストが発生するのでは？と懸念が出なくもないですが、&lt;br /&gt;
これもよほど頭の悪いコンパイラでない限り、outする型に合わせたコードを生成します。&lt;br /&gt;
それに、心配であれば以下のようにしてしまえば確実です。&lt;br /&gt;
『v = ((v &amp;amp; &lt;span style=&quot;color: #cc0000;&quot;&gt;static_cast&amp;lt;T&amp;gt;(0xaaaaaaaa)&lt;/span&gt;) &amp;gt;&amp;gt; 1) | ((v &amp;amp; &lt;span style=&quot;color: #cc0000;&quot;&gt;static_cast&amp;lt;T&amp;gt;(0x55555555)&lt;/span&gt;) &amp;lt;&amp;lt; 1);』 &lt;br /&gt;
これも結局コンパイル時に型が決定するので正しいリテラルになりますね。&lt;br /&gt;
&lt;br /&gt;
というわけで、&lt;br /&gt;
仮に各サイズでこの関数テンプレートが実体化された時の最適化後のコードのイメージは、以下のようになります。 &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
【v == 32bit】
U32 reverseBits(U32 v) {
 v = (v &amp;gt;&amp;gt; 16) | (v &amp;lt;&amp;lt; 16);
 v = ((v &amp;amp; 0xff00ff00) &amp;gt;&amp;gt; 8) | ((v &amp;amp; 0x00ff00ff) &amp;lt;&amp;lt; 8);
 v = ((v &amp;amp; 0xf0f0f0f0) &amp;gt;&amp;gt; 4) | ((v &amp;amp; 0x0f0f0f0f) &amp;lt;&amp;lt; 4);
 v = ((v &amp;amp; 0xcccccccc) &amp;gt;&amp;gt; 2) | ((v &amp;amp; 0x33333333) &amp;lt;&amp;lt; 2);
 v = ((v &amp;amp; 0xaaaaaaaa) &amp;gt;&amp;gt; 1) | ((v &amp;amp; 0x55555555) &amp;lt;&amp;lt; 1);
 return v;
}
【v == 16bit】
U16 reverseBits(U16 v) {
 v = ((v &amp;amp; 0xff00) &amp;gt;&amp;gt; 8) | ((v &amp;amp; 0x00ff) &amp;lt;&amp;lt; 8);
 v = ((v &amp;amp; 0xf0f0) &amp;gt;&amp;gt; 4) | ((v &amp;amp; 0x0f0f) &amp;lt;&amp;lt; 4);
 v = ((v &amp;amp; 0xcccc) &amp;gt;&amp;gt; 2) | ((v &amp;amp; 0x3333) &amp;lt;&amp;lt; 2);
 v = ((v &amp;amp; 0xaaaa) &amp;gt;&amp;gt; 1) | ((v &amp;amp; 0x5555) &amp;lt;&amp;lt; 1);
 return v;
}
【v == 8bit】
U8 reverseBits(U8 v) {
 v = ((v &amp;amp; 0xf0) &amp;gt;&amp;gt; 4) | ((v &amp;amp; 0x0f) &amp;lt;&amp;lt; 4);
 v = ((v &amp;amp; 0xcc) &amp;gt;&amp;gt; 2) | ((v &amp;amp; 0x33) &amp;lt;&amp;lt; 2);
 v = ((v &amp;amp; 0xaa) &amp;gt;&amp;gt; 1) | ((v &amp;amp; 0x55) &amp;lt;&amp;lt; 1);
 return v;
}
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
2012/10/13 細かな加筆修正（内容は変更なし）&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/7647083945674958390/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post_13.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/7647083945674958390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/7647083945674958390'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post_13.html' title='ビット逆転アルゴリズムのテンプレート化と最適化について'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-2885120617504299393</id><published>2012-10-06T03:59:00.002+09:00</published><updated>2012-10-27T21:43:27.607+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><category scheme="http://www.blogger.com/atom/ns#" term="Win32 API"/><category scheme="http://www.blogger.com/atom/ns#" term="ゲーム"/><category scheme="http://www.blogger.com/atom/ns#" term="コマンドプロンプト"/><category scheme="http://www.blogger.com/atom/ns#" term="ソース"/><title type='text'>コマンドプロンプトゲーム - Card Chain</title><content type='html'>暇を持て余しているときにコマンドプロンプトでゲーム作りました。&lt;br /&gt;
&amp;nbsp;（一応完結しているが、完全な実装ではないのでver.0.8.0）&lt;br /&gt;
&lt;br /&gt;
実行ファイルとソースのセットです。&lt;br /&gt;
&lt;br /&gt;
なお、ソースはVC++ 2010 Expressのプロジェクト付きです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
■　カードチェイン&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguESiIbEbkk3qHwQ3PWhQ5gHlfabyzTHqdRn6s7jaYlwMDwNQTQm1dJq8lYEGQK1OLqRVZYfzBzPz516gWTV-z6O6WaPkDRO-jlLdis53bw-QxRslR_e78EKUGmwUkF03ikwtq5NP5Zyw/s1600/CardChain.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;228&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguESiIbEbkk3qHwQ3PWhQ5gHlfabyzTHqdRn6s7jaYlwMDwNQTQm1dJq8lYEGQK1OLqRVZYfzBzPz516gWTV-z6O6WaPkDRO-jlLdis53bw-QxRslR_e78EKUGmwUkF03ikwtq5NP5Zyw/s320/CardChain.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
▽ Download ▽&lt;br /&gt;
&lt;a href=&quot;https://docs.google.com/file/d/0Bz1zlwZ1RkLWR3FvdVROZFZoaXc/edit&quot;&gt;https://docs.google.com/file/d/0Bz1zlwZ1RkLWR3FvdVROZFZoaXc/edit&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
■　作成環境&lt;br /&gt;
　・Mac（Parallels上にインストールしたWindows XP） &lt;br /&gt;
　・VC++ 2010 Express&lt;br /&gt;
　・Win32 API &lt;br /&gt;
&lt;br /&gt;
■　動作確認環境&lt;br /&gt;
　・Windows XP、Windows 7&lt;br /&gt;
　・Mac（Parallels上にインストールしたWindows XP, Windows 8）&lt;br /&gt;
&lt;br /&gt;
■　説明&lt;br /&gt;
&amp;nbsp;　１．概要&lt;br /&gt;
　　・１人用のカードゲーム&lt;br /&gt;
　　・「WhatIf?」だとか、後継の「COOL 104」とルールはほぼ同じ&lt;br /&gt;
　　・同じ数字か同じ柄のカードを、出来るだけ多く選択します。 &lt;br /&gt;
　　・ただし、役によるボーナスなどはありません&lt;br /&gt;
　　・５２枚の全てのカードを出しきればクリア&lt;br /&gt;
　　・１０枚以上続けることができて、初めて得点 &lt;br /&gt;
&lt;br /&gt;
　２．操作方法&lt;br /&gt;
　　・ESCキーでゲームを終了します&lt;br /&gt;
　　・左右キーでカードを選びます&lt;br /&gt;
　　・ ENTER、Z、スペースのいずれかでカードを決定します&lt;br /&gt;
&lt;br /&gt;
■　ライセンス&lt;br /&gt;
　「source」フォルダ内の「lib」フォルダ内のファイルを除き、&lt;br /&gt;
　その他の全てのソースファイルは、改変・再配布自由です。&lt;br /&gt;
&lt;br /&gt;
　ただし、 このプログラムは乱数生成にメルセンヌ・ツイスタを使用しています。&lt;br /&gt;
　ソースファイルに含まれる「lib」フォルダに含まれているものがそれです。&lt;br /&gt;
　この部分に関して、ライセンスは以下のページをご参照ください。&lt;br /&gt;
　&lt;a href=&quot;http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html&quot; target=&quot;_blank&quot;&gt;Mersenne Twister&lt;/a&gt; &lt;br /&gt;
　&lt;br /&gt;
　このゲームではメルセンヌ・ツイスタの関数宣言・定義の一部を改変しています。 &lt;br /&gt;
　ご使用をお考えの場合は、上記のページにてオリジナルを入手しご使用下さい。 &lt;br /&gt;
&lt;br /&gt;
■　免責&lt;br /&gt;
　作者は、このプログラムを使用して起きた不都合・不利益について、&lt;br /&gt;
　一切の責任を負いません。ご容赦ください。&lt;br /&gt;
&lt;br /&gt;
■　連絡事項&lt;br /&gt;
　面白そうなご意見や、ダメ出しや、質問等などあれば、&lt;br /&gt;
　下記コメント欄やメールなど、状況に応じた方法でご連絡ください。&lt;br /&gt;
&lt;br /&gt;
■　ソースに関して　ひとこと&lt;br /&gt;
　・new とかdeleteとか一切不使用なのはそういう作りです。念のため。</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/2885120617504299393/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/10/card-chain.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/2885120617504299393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/2885120617504299393'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/10/card-chain.html' title='コマンドプロンプトゲーム - Card Chain'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguESiIbEbkk3qHwQ3PWhQ5gHlfabyzTHqdRn6s7jaYlwMDwNQTQm1dJq8lYEGQK1OLqRVZYfzBzPz516gWTV-z6O6WaPkDRO-jlLdis53bw-QxRslR_e78EKUGmwUkF03ikwtq5NP5Zyw/s72-c/CardChain.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5416910919127317318.post-5644954147541623046</id><published>2012-10-06T02:15:00.001+09:00</published><updated>2012-10-06T02:15:10.584+09:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="紹介"/><category scheme="http://www.blogger.com/atom/ns#" term="駄文"/><title type='text'>このブログについて</title><content type='html'>暇をみつけて作ったゲームとかを公開。&lt;br /&gt;
偶にソース付き。&lt;br /&gt;
&lt;br /&gt;
というか使い方がよくわからない。&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tama012.blogspot.com/feeds/5644954147541623046/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/5644954147541623046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5416910919127317318/posts/default/5644954147541623046'/><link rel='alternate' type='text/html' href='http://tama012.blogspot.com/2012/10/blog-post.html' title='このブログについて'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00975186559603610649</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>