PSP xvi

PSPプログラミングを教えるブログ(本気で頑張る人アクセス大歓迎サイト)

PSP-X.gif

記事の間違いを報告  新アップローダー
記事修正情報 PSPプログラミング資料 自作ゲーム PSP用エミュレータ リンク

公認リンク
公式PSP専科 公式PSVita専科 はじめるPSPSDK PSP EXEC GAME M@STER PSP 猫山のYouTubeチャンネル

TAG
全記事にタグをつけています  http://nekoyama2gillien.blog36.fc2.com/?tag=タグ
PSP PSPプログラミング DXライブラリPortable OSLib ショートプログラム ハローワールド
PSP自作ゲーム PSP自作ソフト エミュレータ ゲームアーカイブス PSP動画
動画 初音ミク ミクミクダンス MMDドラマ ゲーム 魔法少女まどか☆マギカ 侵略!イカ娘
アイドルマスター

このブログについて

このブログでは、非公式のPSPソフト、いわゆる自作ソフト( PSP Homebrew )を作る事を目的とします。

著作権などの こまかい利用規約については、こちらを開いてお読み下さい

このブログについて知りたい方、初めて来訪された方はこちらを開いてお読みください
お問い合わせは 猫山猫宗(nekomune@gmail.com)までどうぞ


当ブログはリンクフリーです。ブログ名は、アルファベットで「PSP xvi」と書いて『ピーエスピー・エクシビ』とお読みください。
相互リンクを希望されるブログ運営者様は、ココで申請して下さい。


このブログで全記事から探し物の方は、ここをクリックして下さい。
http://nekoyama2gillien.blog36.fc2.com/?all

スポンサーサイト 

--/--/--
--. --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[edit]

CM: --
TB: --

page top

PSP2 の概要が判明!? 

2009/06/01
Mon. 16:40


これが 『PSP Go == PSP2』 だッッ!!


えーと、PSP2 の情報でっす。


-- 続きを読む --
関連記事
スポンサーサイト

[edit]

CM: 0
TB: 0

page top

2009年10月25日、ようやく間違いを訂正。 下の RGB( ) の計算式の閉じカッコが一文字抜けてました。
2010年01月10日、また間違いを訂正。 PSPSDK での int は、32ビット値(固定)です。今まで放置していてご迷惑をおかけしました。


さて、いよいよ お楽しみのグラフィック描画にチャレンジします。
まず今回は、PSPのグラフィック・ビデオRAM(V-RAMとも呼ばれます)を 32ビットカラーモードで点を打つ際の基礎からレッスンです。
これを理解すれば、V-RAMに線を引いたり四角枠や円を描いたり、塗りつぶし長方形や塗りつぶし円を描いたりする事が出来ます
(円を描く際は、数学のSin・Cos等の関数を用いて演算処理をして描画します→CPUでV-RAMに描画する場合であり、GPU描画を行なわない場合)。

 まず、32ビットカラーとは4バイトの値です。実際には現在のパソコンと同じく 24ビットカラー(最大1677万7216色)の表現が出来ますね。
 24ビットカラーと32ビットカラーの違いは、本当は24ビットカラーであり32ビット中 上位8ビットがカラッポの正味24ビットの値でありPSPのような32ビットCPU系では32ビット単位で扱うと楽チンな値でもあります。

 で、32ビットは4バイトなのでキャスト(型宣言)は long を使うと良いでしょう。 int でも良いのです。


 以下、PSPにおける、32ビットカラー(本質24ビットカラー)の割り当て配分表を書いてみます。

ビット  桁

 32 : 8    ↑
 31 : 7    |
 30 : 6    |
 29 : 5    |
 28 : 4 無効なビット(常にゼロ) +3バイト目 (オフセット値3)
 27 : 3    |
 26 : 2    |
 25 : 1    ↓

 24 : 8       
 23 : 7    
 22 : 6    
 21 : 5    
 20 : 4   青成分  +2バイト目 (オフセット値2)
 19 : 3    
 18 : 2    
 17 : 1       

 16 : 8       
 15 : 7    
 14 : 6    
 13 : 5    
 12 : 4   緑成分  +1バイト目 (オフセット値1)
 11 : 3    
 10 : 2    
 09 : 1       

 08 : 8       
 07 : 7    
 06 : 6    
 05 : 5    
 04 : 4   赤成分  +0バイト目 (オフセット値0)
 03 : 3    
 02 : 2    
 01 : 1       


↑↑ 縦長で見づらいかも知れません。ごめんなさい。

青、緑、赤は、それぞれ 8ビット長(1バイト)です。
値は、10進数で 0~255、16進数で 0x00~0xFF の範囲です。

これは、とても計算しやすいかと思いますが、どうですか?

例を挙げると、
青色を指定する際は、コード 0x00FF0000 を渡します。
緑色を指定する際は、コード 0x0000FF00 を渡します。
赤色を指定する際は、コード 0x000000FF を渡します。
と なります。

この時、良く考えてみると、
点を打つ V-RAMアドレスからの距離 赤は+0   (オフセット値==0)
点を打つ V-RAMアドレスからの距離 緑は+1   (オフセット値==1)
点を打つ V-RAMアドレスからの距離 青は+2   (オフセット値==2)
点を打つ V-RAMアドレスからの距離 ダミーは+3 (オフセット値==3)

となるので、仮にPSPの 左上( 0, 0) のV-RAMアドレスの先頭は 0x44000000 なので

0x44000000: 赤成分
0x44000001: 緑成分  (x,y)=(0,0)
0x44000002: 青成分
0x44000003: カラッポ
0x44000004: 赤成分
0x44000005: 緑成分  (x,y)=(1,0)
0x44000006: 青成分
0x44000007: カラッポ
0x44000008: 赤成分
0x44000009: 緑成分  (x,y)=(2,0)
0x4400000A: 青成分
0x4400000B: カラッポ

となるのですが、キャスト(型宣言)long 若しくは int で定義した値で座標(0,0)に色の点を 打つなら、

0x44000000: (long) 空青緑赤

の構成で点が打たれます。まぁ、こういう難しい事は考えずに、long 定義の値で そのままV-RAM書き込みしてやれば良いとだけ記憶しておいて下さい。 ノシ


色のコード対応表とかは、続きに記載する事にします。興味ある人は読んで下さい。
#define でカラーコードを定義して、プログラム中で使えるようにしています(コピペ対応)。

→ PSPプログラミング - 32ビットカラーで描画しよう!その1(後編 / 座標) へ続きます。
今回はダウンロード物はありません。
コピペできる物だけ あります。


-- 続きを読む --
関連記事

[edit]

CM: 0
TB: 0

page top

前回、32ビットカラーについて 詳しく解説したので、今回は V-RAM のアドレス等について詳しく書きます。
PSPの画面解像度は、横:480ピクセル×縦:272ピクセルですが、V-RAM構成横:512ピクセル×縦:272ピクセルとなっています。
中途半端な数値ですねwwwwww

でも、512(10進数)は 0x200(16進数)、272(10進数)は 0x110(16進数)なので、コンピュータにとっては都合の良い数値なのですよ。ふふふ(笑)。

で、実際に V-RAM は どういう構成か書くと、32ビットカラーモードの場合、画面左上(0,0)がV-RAM先頭で、順に右端へ+4(色のバイト数だけプラス)で座標(1,0)のV-RAMアドレスになり、1ラインは512x4(色のバイト数) = 2048バイトです、(0,1)は 先頭V-RAM に2048を足した値です、PSP の V-RAM は2メガ(2,228,224)バイトです(0x220000)、となります。

これを踏まえて、32ビットカラーモードでの、(X,Y)座標から V-RAMのアドレス(オフセット値)を求める計算式を書きます。

     こたえ = ( X + ( Y x 512 )) x 4
      展開して   Xx4 + Yx2048


Xはそのまま足して、Yは単純に512倍すれば良いのです。それらを色のバイト数(32ビットカラーは4バイト)分の数値だけ掛けてやれば良い、という事。
つまり、X を 4倍して、Y を 2048倍する。

が しかし、人間もコンピュータも、掛け算 割り算 は足し算 引き算の繰り返しで答えを求めている、という事実。文字の表示処理の度に、毎回 2048倍 などしていたら処理速度が遅くなります(2048回 足している、という罠)。

そこで、C言語 C++言語 にある シフト演算というのを使ってみます。

   書き方の例
        a=a<<n      b=b>>n

シフト演算というのは、値を 2進数で考えて上位方向(左)や下位方向(右)へ nビット ずらす(移動させる)、という演算です。
シフト演算は 演算を行なう変数のキャストにより、算術演算になったり論理演算になったりします。
下位(右)方向への算術シフト演算では符号ビットの値は複写されます。


よって、下位(右)方向への算術シフト演算の場合は、一番左(最上位ビット)が 1(マイナス)の場合は右に1ビット シフトすると、全部のビットが右に1ビットずれて 最上位ビットに 符号ビットである 1(マイナス)が複写されます。

例1:
int x = 0x80000000;
x=x>>1;

  x の値(実行結果)
   2進数:10000000 00000000 00000000 00000000 16進数:0x80000000
              ↓
       下位(右)方向に1ビット分シフト
              ↓
   2進数:11000000 00000000 00000000 00000000 16進数:0xC0000000

  ◆ x の値は 0xC0000000 になりました。

例2:
int x = 0xA0000000;
x=x>>1;

  x の値(実行結果)
   2進数:10100000 00000000 00000000 00000000 16進数:0xA0000000
              ↓
       下位(右)方向に1ビット分シフト
              ↓
   2進数:11010000 00000000 00000000 00000000 16進数:0xD0000000

  ◆ x の値は 0xd0000000 になりました。


一方、上位(左)方向へのシフト演算の場合は、符号ビットに関係なく、そのまま全部のビットがずれます。空いたビット(右側から順に、のビット)には0が入ります。符号の変化に気をつけて下さい。

例3:
int x = 0x80000000;
x=x<<1;

  x の値(実行結果)
   2進数:10000000 00000000 00000000 00000000 16進数:0x80000000
              ↓
       上位(左)方向に1ビット分シフト
              ↓
   2進数:00000000 00000000 00000000 00000000 16進数:0x00000000

  ◆ x の値は 0 になりました。これはオーバーフロー(桁あふれエラー)です。


アセンブラ言語では、左にシフトしてハミ出たビットが右から順に入る、という 輪っか みたいな概念の ローテート演算というのがありますが、シフト演算は 輪っかという概念が無く、ハミ出たらそれまで! 空いた部分は0 か符号ビットの複写を入れとけ! という演算です。

(シフト演算の演算結果同士を 論理和 でくっつけて、ローテート演算が実現できたりします)

算術シフトの場合、
上位方向(左)へ n ビットシフト演算すると、値が 2のn乗倍になります。
下位方向(右)へ n ビットシフト演算すると、値が 2のn乗分の1倍になります。

  例 1  6<<5
       6を5ビット分、左へ算術シフト演算

   (1ビット分、左へシフト)  6の 2倍 =  12
   (2ビット分、左へシフト)  6の 4倍 =  24
   (3ビット分、左へシフト)  6の 8倍 =  48
   (4ビット分、左へシフト)  6の16倍 =  96
   (5ビット分、左へシフト)  6の32倍 = 192
    答え   192

  例 2  4096>>7
       4096を7ビット分、右へ算術シフト演算

   (1ビット分、右へシフト)  4096の 2分の1 =  2048
   (2ビット分、右へシフト)  4096の 4分の1 =  1024
   (3ビット分、右へシフト)  4096の 8分の1 =  512
   (4ビット分、右へシフト)  4096の 16分の1 =  256
   (5ビット分、右へシフト)  4096の 32分の1 =  128
   (6ビット分、右へシフト)  4096の 64分の1 =  64
   (7ビット分、右へシフト)  4096の128分の1 =  32
    答え    32



そんな訳で、シフト演算を用いて、座標の計算を書くと、下記の様になります。

                 (X + ( Y x 512 )) x 4
               = ( X + ( Y<< 9 ))<<2
               = X<<2 + Y<<11

                 ↑↑ すっきりしました(笑)


PSP画面の V-RAMアドレス は、0x04000000 からで、オフセット値が 0x40000000 で、フレームサイズは 0x88000 バイト あるので、コレを考慮して V-RAMアドレス を求めると、

define FRAMESIZE 0x88000 //in byte
char *pg_vramtop=(char *)0x04000000;

pg_vramtop+(pg_drawframe?FRAMESIZE:0)+(x<<2)+(y<<11)+0x40000000


という計算でおっけーです。
途中の演算 pg_drawframe?FRAMESIZE:0 というのは、
pg_drawframeなら FRAMESIZE つまり、0x88000
pg_drawframeなら
という値を取得する式です。こういう使い方をするモノだと覚えておけば良いでしょう。



『画面を青く塗りつぶすプログラム』 実行画面
FILL_BLUE_sample00.png



『画面を青く塗りつぶすプログラムソース』の一部抜粋を見たい方は続きを読んで下さい。
画面を青く塗りつぶすプログラムのダウンロード
Fill_Blue.zip  123 KB (126,854 バイト)
DOWNLOAD
(ソースのコンパイルには、全角文字表示ライブラリが必要)
(ソースコード付き / CFW用の実行ファイル付き)


-- 続きを読む --
関連記事

[edit]

CM: 0
TB: 0

page top

アイドルマスターSP カタログ5号 

2009/06/08
Mon. 08:01

PSPアイドルマスターSP』の、その後のニュースです。

バンダイナムコゲームスは、PSP用ソフト『アイドルマスターSP(エスピー) パーフェクトサン/ワンダリングスター/ミッシングムーン』のダウンロードコンテンツ (DLC)第5弾を、09年6月10日より配信する。


-- 続きを読む --
関連記事

[edit]

CM: 0
TB: 0

page top

さて、グラフィックの概念を勉強したので、画面に点を打ってみる事にします。ワーイ!

点を打つ、という処理は、(X,Y)座標から V-RAM アドレスを求めて、そのアドレスに long キャストのカラーコードを代入する事で、出来ます。

unsigned char *vptr0; // V-RAM へのポインター
vptr0 = pgGetVramAddr(x,y); // (x,y)座標から、V-RAMアドレスを取得(自作サブルーチン)
*(unsigned long *)vptr0 = 0xFFFFFF; // 白色でドット打ち

          ↑↑ こういう処理で、可能 wwwwwwwww

簡単なのでツマラナイかも知れませんね。
そこで、ドットを十字キーで動くようにしてみます。
1ドット単位で動かすと めっちゃ遅いので、可変ドット単位で移動できるようにしてみます。

      カタカタカタ…………(タイピング音)

ハイ、出来ました(続きを読むでソースの一部が読めます)。


『ドット打ち&ドット移動プログラムのサンプル』実行画面
MOVE_DOT.png

『ドット打ち&ドット移動プログラムのサンプル』のダウンロード
MOVE_DOT.zip  239 KB (244,915 バイト)
ダウンロード
(ソースのコンパイルには、全角文字表示ライブラリが必要)
(ソースコード / CFW用の実行ファイル)
ユーザーモード版EBOOT.PBPです。


-- 続きを読む --
関連記事

[edit]

CM: 1
TB: 0

page top

グラフィック画面に点が打てましたので、線を引いたり図形を描画しようかと考えたんですが、そういう作業は、グラフィック機能を見せつけるゲームとかでないとお目見えしない様です。
そいうのんは、PSPSDKの sceGuDrawArray( )関数 を使えば実現できます。GPUを使います。その件は各自で、勉強して下さい。

今回は、Windows標準のビットマップ画像をPSPで表示する、という事を勉強します。

まずは、Windows標準のビットマップ画像のファイル構造を調べてみましょう。
以下。


Windows bitmap - Wikipedia
ビットマップ画像 - Wikipedia
Bitmapファイルフォーマットの資料
-- BMP形式入門 - BMPファイルの中身をちょっと覗いてみる --


ビットマップ画像ファイルは、基本的には、先頭のヘッダー部分と、ビットマップ画像部分の定められたデータ長(1ピクセルあたりのビット数)で構成されており、表示されている画像の画素情報を 非圧縮で そのまま データにしている、という事実。
つまり、24ビットカラーのビットマップ画像の場合、画像データ本体を3バイトづつ(RGB)読んでV-RAM に貼り付ける事で、ビットマップ画像上の1ドットが打てる、という事です(ヘッダー部分は無視するものとします)。
(32ビットカラーのビットマップ画像の場合は4バイトづつ読み込み)

そうそう、PSPとWindowsでは、RGBとBGRの様に、V-RAMの構成が 赤と青の配置が逆ですので そこら辺 注意のこと。


では、完成したプログラムをどうぞ([ 続きを読む ] でプログラムの一部が見れます)。

今回の見どころ

・ファイル操作(BITMAPファイルのオープン、読み込み、クローズ)
・全角文字ライブラリへの機能追加(文字背景色を指定できる様になりました / 透明色も指定可能)


サンプル画像として、私の製作したシュワちゃんPSP壁紙を 24ビットカラーBITMAP画像に変換したのんを同梱しました。


『PSP画面に ビットマップ画像を描画するプログラム』実行画面
SS20090617A.png

↓↓ このBITMAP画像をPSP画面へ表示するッッ!!
SS20090617B.jpg


『PSP画面に ビットマップ画像を描画するプログラム』のダウンロード
DISP_BITMAP_src.zip  363 KB (371,749 バイト)
ダウンロード
(ソースのコンパイルには、全角文字表示ライブラリが必要)
(ソースコード / CFW用の実行ファイル)
ユーザーモード版EBOOT.PBPです。

PSP壁紙(480x272)を、24Bitカラー・ビットマップ画像に変換した画像
(~.BMP)を、このソフトで表示する事が可能でっす!
但し、ファイルは "ms0:/PICTURE/TEST.bmp" 限定。


-- 続きを読む --
関連記事

[edit]

CM: 2
TB: 0

page top

WindowsプロフェッショナルゲームプログラミングWindowsプロフェッショナルゲームプログラミング
(2002/06)
やね うらお

商品詳細を見る


Windowsプロフェッショナルゲームプログラミング2【CD-ROM付】 (Game developer books)Windowsプロフェッショナルゲームプログラミング2【CD-ROM付】 (Game developer books)
(2003/09/01)
やね うらお

商品詳細を見る


現在、高額値が付いています。


やねうらお氏のホームページ
BM98'S ROOMつう

やねうらお氏のブログ
やねうらお-よっちゃんイカを食べながら年収1億円稼げる(かも知れない)仕事術

ゲーム制作は、これで決まり!
yaneuraoGameSDK series


氏は、フリーソフト 音ゲー「BM98」の開発者。 yaneuraoGameSDK3rd は、とても斬新なのです。
ゲームを開発したい方は是非、この2冊を購入してみるべし。



ボっ、ボクもPSPゲームプログラミング(仮称)という本を出版したいゾ、と。

関連記事

[edit]

CM: 2
TB: 0

page top

※※※※※  重要事項  ※※※※※

ある 神プログラマー様にご意見を伺ったところ、「シフト演算の部分に誤りがあるよん」と指摘されました。ついポカミスしそうなのでよーく考えてみました。で、修正しましたので気になる方は読み返して下さい。
ご指摘ありがとうなのです、神プログラマー様!!


神プログラマー様 に 頂いたURL ↓↓
http://ja.wikipedia.org/wiki/ビット演算
ココを見ると、ビット操作について詳しく書かれています。ナイスですっ!神プログラマー様 !!


私はまたもや ポカミス をしてしまったのです……………。
今度こそ、正しい事を書きます。


今回使った物 ↓↓
Minimalist PSPSDK v0.8.10 (PSPソフト開発キット / C++コンパイラ)

MAKEFILE のコンパイルオプション ↓↓
CFLAGS = -Wall -G0 -O2 -fomit-frame-pointer -mgp32 -mlong32


■■■■■ 右へシフト ■■■■■
main() // 論理シフト
{
unsigned int i; // 符号無し

i = 0xC0000000;
printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>1; // 下位(右)方向へ1ビット分シフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:C0000000 10進数:-1073741824
16進数:60000000 10進数:1610612736

解説
論理演算なので、最上位ビットには 0 が入る(基本パターン)
算術演算ではありません!!
2進数:11000000 00000000 00000000 00000000 b = 16進数:0xC00000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ1ビット分シフト
2進数:01100000 00000000 00000000 00000000 b = 16進数:0x600000000


main() // 算術シフト
{
int i; // 符号あり

i = 0xC0000000;
printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>1; // 2分の1倍
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:C00000000 10進数:-1073741824
16進数:E00000000 10進数:-536870912

解説
算術演算なので、最上位ビットには符号ビットがコピーされて入る(ちょっと考えさせられるパターン)
10進数で見ると、ちゃんと2分の1倍になっています
2進数:11000000 00000000 00000000 00000000 b = 16進数:0xC00000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   2分の1倍
2進数:11100000 00000000 00000000 00000000 b = 16進数:0xE00000000


main() // 論理シフト
{
unsigned int i; // 符号無し

i = 0xC0000000;

printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>2; // 下位(右)方向へ2ビット分シフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:C00000000 10進数:-1073741824
16進数:300000000 10進数:805306368

解説
論理演算なので、最上位ビットには 0 が入る(基本パターーン)
4分の1倍ではありません!(符号注意)
2進数:11000000 00000000 00000000 00000000 b = 16進数:0xC00000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ2ビット分シフト
2進数:00110000 00000000 00000000 00000000 b = 16進数:0x300000000


main() // 算術シフト
{
int i; // 符号あり

i = 0xC0000000;
printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>2; // 4分の1倍
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:C00000000 10進数:-1073741824
16進数:F00000000 10進数:-268435456

解説
算術演算なので、最上位ビットには符号ビットがコピーされて入る
ちゃんと4分の1倍になっています
2進数:11000000 00000000 00000000 00000000 b = 16進数:0xC00000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   4分の1倍
2進数:11110000 00000000 00000000 00000000 b = 16進数:0xF00000000


main() // 論理シフト
{
unsigned int i; // 符号無し

i = 0xFFFFFFFF;
printf("10進数:%d 16進数:%8X \n",i,i);
i=i>>31; // 下位(右)方向へ31ビットシフト
printf("10進数:%d 16進数:%8X \n",i,i);
}
実行結果
10進数:-1 16進数:FFFFFFFF
10進数:1  16進数:1

解説
31ビット分 シフトして、最上位ビット の 1 だけが残って移動し、値 = 1 になりました
2進数:11111111 11111111 11111111 11111111 b = 16進数:0xFFFFFFFF
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ31ビットシフト
2進数:00000000 00000000 00000000 00000001 b = 16進数:0x00000001


main() // 論理シフト
{
unsigned int i; // 符号無し

i = 0xFA8759E5;
printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>32; // 下位(右)方向へ32ビットシフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:FA8759E5 10進数:-91792923
16進数:FA8759E5 10進数:-91792923

解説
おや?変化がない??(値が変わってませんよ??)
2進数:11111010 10000111 01011001 11100101 b = 16進数:0xFA8759E5
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ32ビット分 シフト??
2進数:11111010 10000111 01011001 11100101 b = 16進数:0xFA8759E5


main() // 0 ビット右シフトはどうなるか?(実験1)
{
unsigned int i; // 符号無し

i = 0x4E5D7A05; // 適当な数値(何でも可能)
printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>0; // 下位(右)方向へ 0ビットシフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:4E5D7A05 10進数:1314748933
16進数:4E5D7A05 10進数:1314748933

解説
変化がありません(0 ビットシフトは、2の0乗倍なので1倍です。変化なしは当然)。
ビット移動してませんから、ね。
2進数:01001110 01011101 01111010 00000101 b = 16進数:0x4E5D7A05
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ 0ビットシフト
2進数:01001110 01011101 01111010 00000101 b = 16進数:0x4E5D7A05


main() // 0 ビット左シフトはどうなるか?(実験2)
{
unsigned int i; // 符号無し

i = 0x12345678; // 適当な数値(何でも可能)
printf("16進数:%8X 10進数:%d \n",i,i);
i=i<<0; // 上位(左)方向へ 0ビットシフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:12345678 10進数:305419896
16進数:12345678 10進数:305419896

解説
変化がありません(0 ビットシフトは、2の0乗倍なので1倍です。変化なしは当然)。
下位(右)方向へ 0ビットシフトと同じ結果でした。
2進数:00010010 00110100 01010110 01111000 b = 16進数:0x12345678
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   上位(左)方向へ 0ビットシフト
2進数:00010010 00110100 01010110 01111000 b = 16進数:0x12345678


main() // 32ビットを越えるビットシフト(実験)
{
unsigned int i; // 符号無し

i = 0xFFFFFFFF;
printf("10進数:%d 16進数:%8X \n",i,i);
i=i>>49; // 下位(右)方向へ49ビットシフト
printf("10進数:%d 16進数:%8X \n",i,i);
}
実行結果
10進数:-1  16進数:FFFFFFFF
10進数:32767 16進数:00007FFF

解説
17ビット分だけ下位(右)方向へシフトしているッ!!!!
ひょっとして、49 を 32 で割った余り = 17 ビット分だけ論理シフトしているのかな?
2進数:11111111 11111111 11111111 11111111 b = 16進数:0xFFFFFFFF
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(右)方向へ17ビット分だけシフト
2進数:00000000 00000000 01111111 11111111 b = 16進数:0x00007FFF


■■■■■ 左へシフト ■■■■■
main() // 算術演算 [正の数の場合]

int i = 123; // 正の値で 123

printf("10進数:%d 16進数:%8X \n",i,i);
i=i<<4; // 16倍
printf("10進数:%d 16進数:%8X \n",i,i);
}
実行結果
10進数: 123  16進数: 7B
10進数:1968  16進数: 7B0

解説
ちゃんと16倍されている
2進数:00000000 00000000 00000000 01111011 b = 16進数:0x00000007B
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   16倍
2進数:00000000 00000000 00000111 10110000 b = 16進数:0x0000007B0


main() // 算術演算 [負の数の場合]
{
int i = -10; // 負の値で -10

printf("10進数:%d 16進数:%8X \n",i,i);
i=i<<2; // 4倍
printf("10進数:%d 16進数:%8X \n",i,i);
}
実行結果
10進数:-10 16進数:FFFFFFF6
10進数:-40 16進数:FFFFFFD8

解説
ちゃんと4倍になっている
2進数:11111111 11111111 11111111 11110110 b = 16進数:0xFFFFFFF6
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   4倍
2進数:11111111 11111111 11111111 11011000 b = 16進数:0xFFFFFFD8


main() // 算術演算 [負の数の場合] 桁あふれ例1
{
int i = 0x90000000;

printf("10進数:%d 16進数:%8X \n",i,i);
i=i<<1; // 2倍
printf("10進数:%d 16進数:%8X \n",i,i);
}
実行結果
10進数:-1879048192 16進数:900000000
10進数:536870912  16進数:200000000

解説
これは、演算結果が 桁あふれ になった為。エラーです。
2進数:10010000 00000000 00000000 00000000 b = 16進数:0x90000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   2倍
2進数:00100000 00000000 00000000 00000000 b = 16進数:0x20000000


main() // 算術演算 [負の数の場合] 桁あふれ例2
{
int i = 0x80000000;

printf("16進数:%8X 10進数:%d \n",i,i);
i=i<<1; // 2倍
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:800000000 10進数:-2147483648
16進数:0  10進数:0

解説
これも、演算結果が 桁あふれ になった為。エラーです。
2進数:10000000 00000000 00000000 00000000 b = 16進数:0x80000000
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   2倍
2進数:00000000 00000000 00000000 00000000 b = 16進数:0x00000000


main() // 32ビットを越えるビットシフト(実験1)
{
unsigned int i = 0xFFFFFFFF;

printf("16進数:%8X 10進数:%d \n",i,i);
i=i<<50; // 上位(左)方向へ 50ビット分シフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:FFFFFFFF 10進数:-1
16進数:FFFC0000 10進数:-262144

解説
これも、50 を 32 で割った余り = 18 ビット分だけ シフトしています
2進数:11111111 11111111 11111111 11111111 b = 16進数:0xFFFFFFFF
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   上位(左)方向へ18ビット分だけシフト
2進数:11111111 11111100 00000000 00000000 b = 16進数:0xFFFC0000


main() // 負の数ビット分シフト(実験1)
{
unsigned int i = 0xFF39E421;

printf("16進数:%8X 10進数:%d \n",i,i);
i=i>>(-3); // 下位(右)方向へ、-3ビット分シフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:FF39E421 10進数:-12983263
16進数:F9CF2108 10進数:-103866104

解説
負の数ビット分のシフトは、逆方向への正の数ビット分のシフトになる様です
2進数:11111111 00111001 11100100 00100001 b = 16進数:0xFF39E421
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   上位(左)方向へ 3ビット分シフト
2進数:11111001 11001111 00100001 00001000 b = 16進数:0xF9CF2108


main() // 負の数ビット分シフト(実験2)
{
unsigned int i = 0xFA47D8B1;

printf("16進数:%8X 10進数:%d \n",i,i);
i=i<<(-8); // 上位(左)方向へ、-8ビット分シフト
printf("16進数:%8X 10進数:%d \n",i,i);
}
実行結果
16進数:FA47D8B1 10進数:-95954767
16進数:0FA47D8B 10進数:16402392

解説
負の数ビット分のシフトは、逆方向への正の数ビット分のシフトになる様です
2進数:11111010 01000111 11011000 10110001 b = 16進数:0xFA47D8B1
↓↓↓↓ ↓↓↓↓ ↓↓↓↓ ↓↓↓↓   下位(左)方向へ 8ビット分シフト
2進数:00001111 10100100 01111101 10001011 b = 16進数:0x0FA47D8B


32ビット以上のシフト演算についての参考文献(神プログラマー様 から頂いたURL)
http://www.cpptalk.net/shifting-bits-shift-32-bits-on-32-bit-int-vt35538.html
抜粋すると、こう書いてあります。
> uint32_t x = 5;
> uint32_t y = x << 32;
> uint32_t z = x << 32;
> 
> In the above example y and z are both still 5. Why is this?

  翻訳 : シフト演算の結果、値が変化しないのは何故?

32ビット長の値(変数)を 32ビット左にシフトして 0 にしたかったんでしょうね、気持ちは解かります。
でも、そういう規則(?)はコンパイラーの設計側での問題なので、プログラマーにはコーディングで頑張るしかないですよ。
こまめにデバッグして調べるしか無いようですね。
コンパイラの変な動作を発見したら、原始的な方法で対処するとかした方が良いかもです。
それと、変テコなプログラムは書かないことが鉄則です!



念の為、もう一回 書いておきます 。
今回使った物 ↓↓
Minimalist PSPSDK v0.8.10 (Win32アプリ / PSPソフト開発キット)

MAKEFILE のコンパイルオプション ↓↓
CFLAGS = -Wall -G0 -O2 -fomit-frame-pointer -mgp32 -mlong32

ちょっと一言

今回、こういう結果になりましたが、他のC++コンパイラでも必ずしもこういう結果になるとは限りません。
更に、同じコンパイラでも、コンパイルオプションが違うと 微妙に異なる実行ファイル(EBOOT.PBPや****.prx)が出来上がるので要注意です。



◆◆◆◆◆  まとめ  ◆◆◆◆◆

・キャスト(型宣言)は正しく記述しましょう。

・シフト演算には、論理演算と算術演算があります。
・論理演算は、符号を無視します。nビットシフト。
・算術演算は、符号を有視します。上位(左)方向へは2のn乗倍。下位(左)方向へは2のn乗分の1倍。
・論理演算か、算術演算かは、指定した 変数のキャストを見れば解かります。

・PSPSDKでの ビットシフト演算の処理は、どうやらシフトするビット数を 32 で割った余りの値だけシフトするっぽいです(多分)。
・32ビット分シフトの場合は、0ビット分シフトという事で変化がありません(PSPSDKで検証)。

・負の数ビット(-n)分のシフトは、逆方向への正の数ビット(n) 分のシフトになる様です
 (例1) num>>(-5) は num<<5 の様に処理される
 (例2) num<<(-7) は num>>7 の様に処理される

値は 32ビット長なので、桁あふれする場合があります。警告!!
 が、しかし、桁あふれしても、PSPはエラーだと気付かないのです。
 桁あふれしたらエラー処理をする、というプログラムにての値チェックをするしか無いようです。

 (シフト演算に桁あふれエラー処理を記述するって、聞いた事ありませんが………)


■■■ コンパイル中のメッセージは良く見て下さい ■■■
32ビットを越えるシフト演算を記述したプログラムソースをコンパイルすると、
warning: left shift count >= width of type
warning: right shift count >= width of type
↑↑のような ウォーニング(警告) が表示されます。

負の数ビット分のシフト演算を記述したプログラムソースをコンパイルすると、
warning: left shift count is negative
↑↑のような ウォーニング(警告)が表示されます。

WARNING は、警告でありまして、エラーではありません。その証拠に、コンパイルが継続します。
神プログラマー様によると、"WARNING"は正しくは ウォーニング と発音するのだそうです。

うーーん、勉強になりました。サンキューですぞ。ウホ。

関連記事

[edit]

CM: 2
TB: 0

page top

ブラウザで遊ぶ 【Kung Fu Remix】 

2009/06/30
Tue. 17:08


『スパルタンX』 ではありません!

クリックで飛びます!

波動拳も使えるスパルタンX風のレトロアクションゲーム 【Kung Fu Remix】
↑↑ 画像クリックで飛びます(注意! 音が出ます)

ブラウザで遊ぶ、スパルタンX風の

アクションゲーム


[ 半角/全角キー ] を押して、半角モードにして下さい。


-- 続きを読む --
関連記事

[edit]

CM: 1
TB: 0

page top


h o m e |


 

2009-06