前回のデモのソースコード
前回公開したデモのソースコードを公開。
デバッグ用コードや見た目が地味で没にしたコードもコメント化されて残ってます。
nasm -f bin -o ファイル名.bin ファイル名.asm
でブートセクタ用バイナリを生成
nasm -dMSDOS -f bin -o ファイル名.com ファイル名.asm
でcomファイルを生成
%ifdef MSDOS origin equ 0x100 %else origin equ 0x7c00 %endif %if 0 %ifdef MSDOS %define DISABLE_VIDEO %endif %endif %ifdef DISABLE_VIDEO %define INT0x10 %else %define INT0x10 int 0x10 %endif %ifdef DEBUG %macro assert_eq 2 cmp %1, %2 je %%skip mov ax, __LINE__ call assert_fail %%skip: %endmacro %macro assert_seg_eq 2 mov ax, %1 cmp ax, %2 je %%skip mov ax, __LINE__ call assert_fail %%skip: %endmacro %else %macro assert_eq 2 %endmacro %macro assert_seg_eq 2 %endmacro %endif BITS 16 ;real mode用のコードを生成. ORG origin ;プログラムが読み込まれるメモリ位置を指定. vd_width equ 320 vd_height equ 200 vd_area equ vd_width*vd_height vd_bpp equ 1 vd_size equ vd_area*vd_bpp ram_segment equ origin+512/16 stack_begin equ 0x1600 ;stackの開始offset. vd_segment equ ram_segment+0x1000 position_frac_part equ 6 position_frac equ 64 ;2^position_frac_part speed_frac_part equ 5 start: mov ax, ram_segment mov ss, ax mov sp, stack_begin ;video mode設定 ;320x200x8bit mov ax, 0x13 INT0x10 ;パレット設定 xor dx, dx mov cx, 0x3f pallets: push cx ; xchg bx, cx ;xchgのオペランドの一方がax,もう一方がレジスタだと1byteなんだけどな. mov bx, cx mov dh, bl ;Red mov ch, bl ;Green ; mov cl, bl ;Blue mov ax, 0x1010 INT0x10 pop cx loop pallets ;internal speakerを初期化する. mov al, 182 out 0x43, al particles equ stack_begin ;offset of particles data bytes_per_particle equ 2*2*3 ;word position x ;word position y ;word speed x ;word speed y ;word accel x ;word accel y max_num_particles equ (0x10000-0x1600)/bytes_per_particle num_particles equ 0x1000;4992 ;305 particles_size equ num_particles*bytes_per_particle %if 0 field_force equ particles+particles_size ;word position x ;word position y ;field force flag; 0:disable, 1:enable field_force_size equ 2+2+1 %endif average equ particles+particles_size old_average equ average+2 old_beep_freq equ old_average+2 ;粒子データ初期化の準備 cld mov ax, ram_segment mov ds, ax mov di, particles mov cx, num_particles pusha %if 0 init_particle: ; mov ax, 4 ; mul cx mov ax, cx shl ax, 2 and ax, 0xff sal ax, position_frac_part mov word [di], ax ;position x mov ax, cx and ax, 0xffff-0x3f shl ax, 3 mov [di+2], ax ;position y xor ax, ax mov [di+4], ax ;speed x mov [di+6], ax ;speed y lea di, [di+bytes_per_particle] loop init_particle %endif ;粒子の位置とか速度とか加速度は全部0にしとけ. mov es, ax mov cx, particles_size xor ax, ax rep stosb step: ; mov ax, vd_segment ; mov es, ax ;esレジスタは常にback surfaceのセグメントを指すようにする. push vd_segment pop es call vd_clear %if 0 ;set field_force mov word [field_force], (vd_width*2/3)*position_frac mov word [field_force+2], vd_height/2*position_frac xor bl, bl ; mov ax, [di+2] ; and al, 255 xor ah, ah int 0x1a ;Real clock count and dl, 0x3f jnz store_field_force mov bl, 0x4 store_field_force: mov byte [field_force+4], bl %endif xor ah, ah int 0x1a ;クロックカウント読み出し. mov fs, dx ;fsは常にクロックカウント値を持つ. popa assert_eq cx, num_particles assert_eq di, particles assert_eq sp, stack_begin pusha ;mov cx, num_particles ;mov di, particles mov ax, fs shl ax, 3 and ax, num_particles-1 sub cx, ax ;粒子の平均速さもどきを更新. xor ax, ax xchg ax, [average] xchg ax, [old_average] for_particles: %if 0 push ax push ax call get_explode_force pop ax add [di+8], ax pop ax add [di+10], ax %endif call dynamics put: push di mov dx, (vd_width-1)*position_frac call integ_comp inc di inc di ;床が下から上がってくるやつ ;それほど面白くないのでボツ. %if 0 xor ax, ax mov bx, fs ; add bx, 0x77 test bl, 0xc0 jnz .integ .mov_wall: xchg ax, bx and ax, 0x3f shl ax, 2 .integ: mov dx, vd_height-1 sub dx, ax shl dx, position_frac_part %else mov dx, (vd_height-1)*position_frac %endif call integ_comp pop si positioning: ;vramでの粒子の位置を計算. mov ax, [si+2] sar ax, position_frac_part mov bx, vd_width mul bx mov bx, [si] sar bx, position_frac_part add ax, bx mov di, ax ;collision mov al, [es:di] cmp al, 0x3f jne puton mov bx, si shr bx, 4 and bx, 0x2 sub word [bx+si], position_frac ;*2 ;メモリに描画して,後で一気にvramへコピーする. ;double buffering. puton: mov al, 0x3f stosb ; mov byte [bx], 0x3f lea di, [si+bytes_per_particle] loop for_particles call vd_flash %if 1 ;FPSがべらぼうに高くならないようにwaitする. ;cx:dx interval in microseconds mov ah, 0x86 xor cx, cx mov dx, 0x2000 int 0x15 %endif ; call speaker_off call music jmp short step ;以下にサブルーチンを定義 vd_clear: mov ax, fs test ax, 0x300 jnz .smoke ;画面を真っ黒にする. pusha mov cx, vd_area/2 xor di, di xor ax, ax rep stosw popa ret .smoke: ;画面をクリアしないけど煙たくする. ;各ピクセルについて,下らへんのピクセル値の平均値を設定 push ds push es pop ds xor bx, bx mov cx, vd_height-2 .vert: push cx mov cx, vd_width ;-1;一番右の垂直ラインがおかしくなるかもしれんが、見た目良ければOK. .line: mov si, cx lea si, [bx+si+vd_width] lodsb shl ax, 8 lodsb add ah, al lea si, [si-2+vd_width] lodsb add ah, al lodsb add ah, al shr ax, 10 lea di, [si-2-vd_width*2] stosb loop .line add bx, vd_width pop cx loop .vert ;一番下のライン2本は黒くしとけ. mov cx, vd_width*2 mov di, bx xor al, al rep stosb pop ds ret ;力学計算っぽいことあれこれ. dynamics: ;di+10はよく使うからsiに入れてコードサイズ節約. lea si, [di+10] ;渦を作るよ. mov ax, fs add ax, 0x80 test ax, 0x100 jz .skip_vortex vortex_force equ 90 mov bx, vortex_force ; test ax, 0x80 neg al js .start_vortex neg bx .start_vortex: push bx mov bx, [di] mov dx, [di+2] mov ax, bx add ax, dx cmp bx, dx ; mov bx, vortex_force pop bx ja .right_area cmp ax, (vd_height-1)*position_frac jae .left_bottom add word [si], bx;left jmp short .break_vortex .left_bottom: add word [di+8], bx jmp short .break_vortex .right_area: cmp ax, (vd_width-1)*position_frac jae .right_right sub word [di+8], bx ;right top jmp short .break_vortex .right_right: sub word [si], bx; jmp short .break_vortex .skip_vortex: mov byte [si], 24 ;重力を設定. %if 1 ;地面にぶつかったら飛び跳ねるやつ. cmp word [di+2], (vd_height-1)*position_frac jb .break_vortex ; mov word [di+2], (vd_height-1)*position_frac ; mov word [di+6], 0 mov word [si], -5900 %endif .break_vortex: ;高速移動 mov dx, fs test dl, 0xff-0x20 ; test dx, 0xff-0x20 jnz .skip_scatter mov ax, [di] mov bx, [di+2] ; sar ax, 2 ; sar bx, 2 mov [di+4], ax mov [di+6], bx .skip_scatter: ;回転 ;粒子の速度に垂直な方向へ力を加えれば速度の向きが変わるだろ 物理的に考えて. %if 1 %if 1 ; mov dx, fs ; test dl, 0x80 ; jnz .skip_rotation neg dl jns .skip_rotation %else ; cmp byte [old_average+1], 0xef ; jb .skip_rotation test byte [old_average+1], 0x40 jz .skip_rotation %endif mov ax, [di+4] mov bx, [di+6] neg bx sar ax, 5 sar bx, 5 add [di+8], bx add [si], ax .skip_rotation: %endif ; mov dx, 2 %if 0 ;矩形コリジョン. rect_len_part equ 4 rect_len equ (1<<rect_len_part)*position_frac pusha ;push cx, push di mov cx, dx .collision_detection: test word [di], rect_len jnz .skip_rect_collision inc di inc di loop .collision_detection popa pusha ; mov cx, dx .avoid_collide: %if 1 mov ax, [di] mov bx, [di+2] add ax, bx test ax, rect_len/2 jnz .upper ; sub ax, rect_len jmp .continue_loop .upper: or ax, rect_len .continue_loop: %endif and ax, ~(rect_len-1) mov [di], ax ; inc di ; inc di ; loop .avoid_collide %if 0 or word [di], (rect_len*position_frac) or word [di+2], (rect_len*position_frac) %endif xor ax, ax ; mov word [di+4], ax neg word [di+4] mov word [di+8], ax ; mov word [di+6], ax .skip_rect_collision: popa %endif ;速度の各成分の絶対値の和を足してくよ. pusha cmp cx, 0xd0;num_particles-0xd0 ; jg .skip_average mov cx, 2 .comp: mov ax, [di+4] sar ax, 8 %if 0 imul al ;速度の2乗だとつまらん音しかでねーよ. %else cmp al, 0 jnb .not_neg neg al .not_neg: %endif add [average], ax inc di inc di loop .comp .skip_average: popa ret ;メインメモリに描画した内容をvramに送る. vd_flash: %ifndef DISABLE_VIDEO push ds push es mov cx, vd_area xor si, si push es pop ds push 0xa000 pop es xor di, di rep movsb pop es pop ds %endif ret ;加速度から速度を更新し、速度から位置を更新する. ;Δt=1ということにしてΔtを掛けるのは端折る. ;args: ; di :particle data pointer ; dx :limit of x or y value integ_comp: ;v=v+t*f/m ;p=p+t*v ;where m=1, t=1 lea si, [di+4] ;speed x mov ax, [si] mov bx, ax ;damping sar bx, 6 sub ax, bx add ax, [di+8] ;accel x mov word [di+8], 0 mov [si], ax ;update speed mov bx, [di] ;position x sar ax, speed_frac_part add bx, ax jns .check_range xor bx, bx neg word [si] .check_range: cmp bx, dx jbe .store mov bx, dx neg word [si] .store: mov [di], bx ret music: %if 0 mov ax, fs and ax, 0x7f or ax, 0x3 sal ax, 6 %else ;粒子の平均の速さもどきに比例した周波数の音をだす. mov ax, [average] neg ax add ax, 0xffff ;音を多少平滑化すれば不快な音もましになるかも・・・. add ax, [old_beep_freq] shr ax, 1 mov [old_beep_freq], ax or al, 0x1f %endif ; call speaker_on ; ax :frequency speaker_on: out 0x42, al mov al, ah out 0x42, al in al, 0x61 or al, 0x3 out 0x61, al ; ret ret %if 0 speaker_off: in al, 0x61 and al, 0xfc out 0x61, al ret %endif %if 0 ; ;return ; pop :力のx値 ; pop :力のx値 get_explode_force: mov bp, sp pusha assert_seg_eq ds, ram_segment mov cx, 2 mov si, field_force xor bx, bx .comp: mov ax, [di] ;position of particle mov dx, [si] ;position of field force sub ax, dx sar ax, 8 push ax imul al add bx, ax ;bx is |particleの位置-field forceの位置|^2 inc di inc di inc si inc si loop .comp shr bx, 8 inc bx ;0での除算を避ける. ; or bx, 32 mov cl, [field_force+4] pop ax idiv bl imul cx mov [bp+4], ax pop ax idiv bl imul cx mov [bp+2], ax popa ret %endif %ifdef DEBUG assert_fail: push ax mov ax, cs mov ds, ax mov ah, 9 mov dx, assert_fail_msg int 0x21 pop ax push '$' mov bx, 10 mov di, 3 mov cx, 4 assert_fail__print_line: xor dx, dx div bx add dx, '0' mov byte [assert_fail_line+di], dl dec di loop assert_fail__print_line mov dx, assert_fail_line mov ah, 9 int 0x21 int 0x20 ret assert_fail_msg: db 'Assertion failed $' assert_fail_line: db 'xxxx$' %endif %ifndef MSDOS times 510-($-$$) db 0 ;0x1feまでを0で埋めるわけだが,このコードには必要ない! db 0x55, 0xaa ;ブートセクタの印. %endif
OSが無くても動くデモ
前回作ったプログラムのブートセクタ版を公開します。
使用するときは自己責任でお願いします。
B8 20 7C 8E D0 BC 00 16 B8 13 00 CD 10 31 D2 B9 3F 00 51 89 CB 88 DE 88 DD B8 10 10 CD 10 59 E2 F1 B0 B6 E6 43 FC B8 20 7C 8E D8 BF 00 16 B9 00 10 60 8E C0 B9 00 C0 31 C0 F3 AA 68 20 8C 07 E8 70 00 30 E4 CD 1A 8E E2 61 60 8C E0 C1 E0 03 25 FF 0F 29 C1 31 C0 87 06 00 D6 87 06 02 D6 E8 A3 00 57 BA C0 4F E8 48 01 47 47 BA C0 31 E8 40 01 5E 8B 44 02 C1 F8 06 BB 40 01 F7 E3 8B 1C C1 FB 06 01 D8 89 C7 26 8A 05 3C 3F 75 0D 89 F3 C1 EB 04 81 E3 02 00 81 28 40 00 B0 3F AA 8D 7C 0C E2 BD E8 F8 00 B4 86 31 C9 BA 00 20 CD 15 E8 2E 01 EB 89 8C E0 A9 00 03 75 0C 60 B9 00 7D 31 FF 31 C0 F3 AB 61 C3 1E 06 1F 31 DB B9 C6 00 51 B9 40 01 89 CE 8D B0 40 01 AC C1 E0 08 AC 00 C4 8D B4 3E 01 AC 00 C4 AC 00 C4 C1 E8 0A 8D BC 7E FD AA E2 DF 81 C3 40 01 59 E2 D4 B9 80 02 89 DF 30 C0 F3 AA 1F C3 8D 75 0A 8C E0 05 80 00 A9 00 01 74 34 BB 5A 00 F6 D8 78 02 F7 DB 53 8B 1D 8B 55 02 89 D8 01 D0 39 D3 5B 77 0E 3D C0 31 73 04 01 1C EB 21 01 5D 08 EB 1C 3D C0 4F 73 05 29 5D 08 EB 12 29 1C EB 0E C6 04 18 81 7D 02 C0 31 72 04 C7 04 F4 E8 8C E2 F6 C2 DF 75 0B 8B 05 8B 5D 02 89 45 04 89 5D 06 F6 DA 79 13 8B 45 04 8B 5D 06 F7 DB C1 F8 05 C1 FB 05 01 5D 08 01 04 60 81 F9 D0 00 7F 17 B9 02 00 8B 45 04 C1 F8 08 3C 00 73 02 F6 D8 01 06 00 D6 47 47 E2 EC 61 C3 1E 06 B9 00 FA 31 F6 06 1F 68 00 A0 07 31 FF F3 A4 07 1F C3 8D 75 04 8B 04 89 C3 C1 FB 06 29 D8 03 45 08 C7 45 08 00 00 89 04 8B 1D C1 F8 05 01 C3 79 04 31 DB F7 1C 39 D3 76 04 89 D3 F7 1C 89 1D C3 A1 00 D6 F7 D8 05 FF FF 03 06 04 D6 D1 E8 A3 04 D6 0C 1F E6 42 88 E0 E6 42 E4 61 0C 03 E6 61 C3 55 AA
このプログラムをqemuというエミュレータ上で動かす方法とUSBメモリを使ってPC上で直接動かす方法を説明する。
・qemuで実行する方法
1, 上記コードをバイナリエディタへコピペする等してファイルに保存。
2, qemu -L . (1で作ったファイル) -soundhw all
(-LでBIOS, VGA BIOS, keymapsファイルのあるディレクトリを指定する。これらはqemuに付属している。-soundhw allでサウンドを有効にする)
・起動用USBメモリを作成して実行する
(PC上で直接動かすので他の方法よりリスクが高いので注意)
http://www.dex4u.com/USBboot.htm
を参考にした方法を使う。
0, 空か消えてもいいデータしか入ってないUSBメモリを用意する
1, 上記ページからHPformatをダウンロードしてインストールする
2, USBメモリを指してHPformatを起動(管理者権限が必要)
3, USBメモリをFAT(FAT32ではない)でフォーマットする
4, 上記ページからHxDをダウンロードしてインストールする
5, HxDを起動(管理者権限が必要)
6, Extrasからremovable disk1を選び"open as readonly"のチェックをはずしてopenする。
7, Sector 0(0~1FF)をすべて上記コードと置き換えます。
8, このまま保存すると起動用USBメモリの完成です。
このUSBメモリを指してPCを起動し,BIOSの画面でfloppy emulationでUSBメモリを起動するように設定。
これでUSBメモリから起動するとデモが動く。
510bytesで何ができるか
PCの電源を入れてからOSが起動するまでをおおまかに説明すると
1, CPUが初期化されてBIOSにあるプログラムが実行される
2, BIOSは設定されたメディア(ハードディスクとかフロッピーディスク等)のブートセクタと呼ばれる最初の512bytesを読み込んでメモリに書き込む
3, メモリに書き込んだ先にジャンプしてそのプログラムを実行する
ここで、ほとんどのOSは512bytesに収まらないのでブートセクタにはさらにメディアからOSを読み込むようなプログラムが置かれている。
そこでブートセクタの512bytesに収まるプログラムの作成に挑戦してみた。
ちなにブートセクタの最後の2bytesには0x55,0xaaがないとブートセクタとは認めて貰えず実行されないので
実質的には510bytesまでしか使えない。
ブートセクタのプログラムが実行されるときはもちろんOSの機能は全く使えないがBIOSに用意された機能を使えば
画面に絵を描いたりすることができるのでメガデモのようなプログラムを作る事にした。
以下に作成したプログラムのバイナリコードを公開する。
実際にOSの無い状態から動かすのは少し面倒なのでまずはcomファイルとして実行できるコードを公開。
このプログラムを実行するのは自己責任でお願いします。
ビープスピーカーから音がでるように作られているので注意。
ms-dos, Windows Vistaより古いwindowsだとそのまま実行できると思うけど
それ以外のOSを使っている人はDOSBox(ms-dosのエミュレータ)等を使って実行して下さい。
直接comファイルを実行するのが不安な人やビープスピーカから音がでるのが嫌な人もDOSBoxを使うといいかも。
B8 20 01 8E D0 BC 00 16 B8 13 00 CD 10 31 D2 B9 3F 00 51 89 CB 88 DE 88 DD B8 10 10 CD 10 59 E2 F1 B0 B6 E6 43 FC B8 20 01 8E D8 BF 00 16 B9 00 10 60 8E C0 B9 00 C0 31 C0 F3 AA 68 20 11 07 E8 70 00 30 E4 CD 1A 8E E2 61 60 8C E0 C1 E0 03 25 FF 0F 29 C1 31 C0 87 06 00 D6 87 06 02 D6 E8 A3 00 57 BA C0 4F E8 48 01 47 47 BA C0 31 E8 40 01 5E 8B 44 02 C1 F8 06 BB 40 01 F7 E3 8B 1C C1 FB 06 01 D8 89 C7 26 8A 05 3C 3F 75 0D 89 F3 C1 EB 04 81 E3 02 00 81 28 40 00 B0 3F AA 8D 7C 0C E2 BD E8 F8 00 B4 86 31 C9 BA 00 20 CD 15 E8 2E 01 EB 89 8C E0 A9 00 03 75 0C 60 B9 00 7D 31 FF 31 C0 F3 AB 61 C3 1E 06 1F 31 DB B9 C6 00 51 B9 40 01 89 CE 8D B0 40 01 AC C1 E0 08 AC 00 C4 8D B4 3E 01 AC 00 C4 AC 00 C4 C1 E8 0A 8D BC 7E FD AA E2 DF 81 C3 40 01 59 E2 D4 B9 80 02 89 DF 30 C0 F3 AA 1F C3 8D 75 0A 8C E0 05 80 00 A9 00 01 74 34 BB 5A 00 F6 D8 78 02 F7 DB 53 8B 1D 8B 55 02 89 D8 01 D0 39 D3 5B 77 0E 3D C0 31 73 04 01 1C EB 21 01 5D 08 EB 1C 3D C0 4F 73 05 29 5D 08 EB 12 29 1C EB 0E C6 04 18 81 7D 02 C0 31 72 04 C7 04 F4 E8 8C E2 F6 C2 DF 75 0B 8B 05 8B 5D 02 89 45 04 89 5D 06 F6 DA 79 13 8B 45 04 8B 5D 06 F7 DB C1 F8 05 C1 FB 05 01 5D 08 01 04 60 81 F9 D0 00 7F 17 B9 02 00 8B 45 04 C1 F8 08 3C 00 73 02 F6 D8 01 06 00 D6 47 47 E2 EC 61 C3 1E 06 B9 00 FA 31 F6 06 1F 68 00 A0 07 31 FF F3 A4 07 1F C3 8D 75 04 8B 04 89 C3 C1 FB 06 29 D8 03 45 08 C7 45 08 00 00 89 04 8B 1D C1 F8 05 01 C3 79 04 31 DB F7 1C 39 D3 76 04 89 D3 F7 1C 89 1D C3 A1 00 D6 F7 D8 05 FF FF 03 06 04 D6 D1 E8 A3 04 D6 0C 1F E6 42 88 E0 E6 42 E4 61 0C 03 E6 61 C3
きっちり510(0x1FD)バイトあるはず。
上記16進数のコードをバイナリエディタへコピペするとかして拡張子がcomとなるファイルを作成して下さい。
と思ったら手元にあるバイナリエディタ(BzとStirling)ではテキストからバイナリをコピペして貼り付けできないようだ。
http://www.mh-nexus.de/hxd/
にあるバイナリエディタだとバイナリを直接コピペしてcomファイルとして保存することができた。
このバイナリエディタはハードディスクとかを直接生でいじれるらしい。
ループカウンタのi,j,k
C言語系ではよく以下のようにループカウンタにi, jという名前の変数を使う。
for(int i=0; i<3; ++i) for(int j=0; j<7; ++j) { printf("%d, %d\n", i, j); }
今まで外側のループカウンタから順番にi, j, k, ...という変数名を付けていたがこのやり方には欠点がある。
以下のようなループが二つあったとして,
//ループ0 for(int i=0; i<3; ++i) { printf("%d\n", i); } //ループ1 for(int i=0; i<7; ++i) { printf("%d\n", i); for(int j=0; j<11: ++j) { printf("-%d\n", i*j); } }
ループ1をループ0の中に入れたくなったとき,以下のようにループ1のi, jをj, kに変更するのは面倒だ。
//ループ2 for(int i=0; i<3; ++i) { printf("%d\n", i); for(int j=0; j<7; ++j) { printf("%d\n", j); for(int k=0; k<11: ++k) { printf("-%d\n", j*k); } } }
ループ1を別関数にしてループ0から呼び出すようにすれば,ループ2を書き換えずに済むが
小さなループのために関数を追加するのも気が引けるし,もしループ1が同じスコープ内の大量の一時変数に依存していると
関数に分けるのも面倒になる。
しかし,外側からi,j,kという変数名を使うというルールを無視すれば
ループ1をそのままループ0内にカトペ(cut&paste)してインデントするだけで済む。
//ループ3 for(int i=0; i<3; ++i) { printf("%d\n", i); //ループ3-1 for(int i=0; i<7; ++i) { printf("%d\n", i); //ループ3-2 for(int j=0; j<11: ++j) { printf("-%d\n", i*j); } } }
しかし上記のループ3-2を今度はループカウンタi,jを使っている2重ループの内側へ移すときには修正が必要になる。
そこで多重ループ内では常にiが現在のスコープのループカウンタ,jが一つ外側のループカウンタ,kがそのまた一つ外側のループカウンタ,
となるようにコードを書くようにする。
例えば以下のようにループを書いておくとループ処理を少しの修正でカトペすることができる。
for(int i=0; i<3; ++i) { printf("%d\n", i); for(int j=i, i=0; i<7; ++i) { printf("%d\n", j*i); for(int k=j, j=i, i=0; i<11; ++i) printf("%d\n", k+j+i); for(int j=i, i=0; i<11; ++i) printf("%d\n", j+i); } }
この方法はC++と(たぶん)C99と(普段使わないのでよく知らないが)java, C#等のC言語系でも使えると思う。
だが、この方法でも深いループでずっと外側までのループカウンタが必要になるときにint l=k, k=j, j=i, i=0と書くのは
少し面倒だ。
C++ならテンプレートとかBoostライブラリを駆使すればもう少し短く書けるような気がするので今度考えてみよう。
cygwinにboostインストールメモ
・前準備
boost 1.35.0ではmpiが使えるようなのでcygwinにmpich2をインストールしてみた。
Pythonが入ってないとconfigureで失敗するので入れておく。
普通にソースコードをゲットして
./configure
make
make install
でインストールできた。
自宅に一台しかPCが無いので複数マシンでmpich2が使えるかは不明。
Boost Iostreamsのbzip2で圧縮/解凍するfilterを使うにはlibbz2-develが必要っぽいのでインストールしておく。
・boostをconfigureする。
以下のファイルの改行がCR+LFになっているためにCygwinではそのまま実行できないので
vim等を使って改行コードをLFへ変換する。
configure
tools/jam/src/build.sh
次に
./configure
を実行
次に
user-config.jamに
using mpi : mpicxx ;
でMPI wrapper compilerの名前を指定する。(configureで自動的に見つけてくれない)
Cygwin上のg++ではwide charは使えないので
libs/serialization/build/Jamfile.v2
のSOURCES=の中のcodecvt_nullの行を削除する。
・ビルドする
make
Serializationのwchar_t関連のファイルでコンパイルエラーがでるが他のライブラリがコンパイルされていれば大丈夫だろう。
bin.v2/lib/以下のディレクトリにビルドされた各ライブラリがあるので確認しておこう。
・インストールする。
make install
./configureしたときに--prefixを指定していなければ/usr/local下のinclude,libにインストールされる。
g++でwcharが使えない
http://d.hatena.ne.jp/gpuppur/20080420
でビルドしたgccでは
boost-1.35.0をビルドするときにboost::serializeのwchar_t関連を使っているファイルでコンパイルエラーがでる。
ググったところ
http://d.hatena.ne.jp/y-hamigaki/20070327
iconv.hがないとlibstd++でwchar_tが有効にならないとの事でインストールすることにした。
cygwinに普通にlibiconvをインストールしただけではiconv.hは手に入らないようだ。
そこでsetup.exeでlibiconvのSrcにペケをつけてソースコードをゲットする。
それとcygportとg++もインストールする。
ソースコードは/usr/src下に置かれるので
cygport libiconv-1.11-1.cygport all
でソースコードをビルドし
tar xjvf libiconv-1.11-1.tar.bz2 -C /
でインストールすると/usr/include/iconv.hが置かれる。
その後gccをビルドし直したが症状が変わらない。
wchar.hのwprintfは使えるが
g++ではwprintfを使おうとしても定義してないよとコンパイルエラーがでる。
objdir/i686-pc-cygwin/libstdc++-v3/config.log
を見たところiconvのチェックはyesになっている。
だがwchar_t specializationsはnoになっている。
もう少しよく調べてg++でwchar関連の関数を使えるようにするべきか、
wchar関連の関数を使わないようにboostをビルドすべきか・・・。
cygwinにgcc-4.3.0(CとC++のみ)をインストールする
cygwinのsetup.exeでは少し古いgcc-3.4.4しかインストールできないようなので現在最新の4.3.0をインストールすることにした。
ここにやり方をメモしておく。
きちんとgccをインストールしたい方はgccのドキュメントを参照して下さい。
必要なpackageのリスト
cygwinのsetup.exeで以下のものをインストールしておく。
download
gcc本家のページからgcc-core-4.3.0.tar.bz2とgcc-g++-4.3.0.tar.bz2をダウンロードし
$ tar xjvf gcc-core-4.3.0.tar.bz2 $ tar xjvf gcc-g++-4.3.0.tar.bz2
configuration
gcc-4.3.0内で作業するのはよろしくないので別のディレクトリ内で作業する。
ここではobjdirを作ってそこで作業する。
$ mkdir objdir $ cd objdir
次にconfigureする
$ ../gcc-4.3.0/configure --enable-languages=c,c++ --enable-threads=posix --enable-version-specific-runtime-libc
configureするときのオプションはcygwinのgcc -vで表示されるのと同じものを指定しておけばたぶん大丈夫だと思うが
今回はcとc++さえ使えればよいので必要なものだけ指定しておく。
buildする
make bootstrapでビルドできるらしいが,デフォルトだと'-g -O2'でコンパイルされる。
デバッグ情報は必要無いと思うのでBOOT_CFLAGS='-O2'を指定することにした。
bootstrap-leanだとビルド中に生成するファイルがいらなくなったらすぐに消されるので必要なディスク容量が減るらしい。
quad core CPUを持ってるけどビルド中にブラウザを使いたいのでオプション'-j 3'を指定することにした。
約1時間でbuildできた。
$ make BOOT_CFLAGS='-O2' -j 3 bootstrap
install
最後に
make install
で完了。