PEEKとPOKE

コンピューティングにおいて、PEEK（ピーク）とPOKE（ポーク）は、いくつかの高水準プログラミング言語で使用されるコマンドで、メモリーアドレスで参照される特定のメモリセルの内容にアクセスするために使用する。BASICのものがよく知られているが、PascalやCOMAL（英語版）など他のプログラミング言語にも同様のコマンドがある。このコマンドは、C言語などにおけるポインタに匹敵する役割を持っている。 PEEKとPOKEは、初期のパーソナルコンピュータにおいて様々な目的を果たすために考案され、特に、メモリ空間にマッピングされたハードウェアレジスタを変更するために使用された。また、プログラマはこのコマンドを使用して、ソフトウェアをコピーしたり、特定のソフトウェアのプログラミングの意図を回避したりすることもある（例えば、ゲームプログラムを操作してユーザがチートできるようにするなど）。今日では、BASICのような高水準言語を使用して、低水準でメモリを制御することはあまりなく、PEEK、POKEというコマンドの概念は一般的に時代遅れとみなされている。 英語においては、peekやpokeという言葉が、プログラミングにおけるメモリアクセスを指す動詞（poked, peekedなど）として口語的に使われることがある。 PEEK関数とPOKEコマンドは、通常、以下のように直接モード（英語版）（BASICプロンプトで入力して即実行）か、間接モード（下記のソースのようにプログラムの中から実行）で呼び出される。 integer_variable = PEEK(address) POKE address, value 引数のaddressとvalueは、評価される式がそれぞれ有効なメモリアドレスまたは値に対応する限り、複雑な式を含んでいても良い。ここで言う「有効なアドレス」とは、コンピュータのアドレス空間内のアドレスであり、「有効な値」とは、（一般的には）ゼロから最小アドレス可能なユニット（メモリセル）が保持することができる最大符号なし数までの符号なし値である。 POKEまたはPEEKされるアドレス位置は、通常のメモリセルや、対応するチップ（I/Oユニット、サウンドチップ、ビデオグラフィックスチップなど）のメモリマップされたハードウェアレジスタ、CPU自体のメモリマップされたレジスタを参照することができる（これにより、強力な機械語モニタやデバッグツール、シミュレーションツールをソフトウェアで実装することが可能になる）。以下は、POKEによる対応チップ制御の一例として、コモドール64の内蔵VIC-II（英語版）グラフィックスチップの特定のレジスタを操作して、画面の境界線を黒くするコマンドの例である。 POKE 53280, 0 以下は、Atari 8ビット・コンピュータでANTIC（英語版）ディスプレイドライバに、全てのテキストを上下逆さまにするように指示するコマンドである。 POKE 755, 4 ハードに紐付けられたメモリ位置は機種によって異なるため、様々な機種の「メモリマップ」は重要な文書である。定型的な例として、アタリのコンピュータの64キロバイトのメモリ全体をロケーションごとにマッピングした本『マッピング・オブ・アタリ（英語版）』が出版されている。 一般的に、ユーザプログラム、ユーザデータ、オペレーティングシステムのコードとデータ、メモリマップされたハードウェアユニットのために指定されたメモリアドレス領域は、機種によって異なる。このため、PEEK関数やPOKEコマンドは本質的に非移植性であり、これらを使用したプログラムは、そのプログラムが書かれたシステム以外ではほぼ確実に動作しない。 多くの8ビットコンピュータ用ゲームにおいては、ゲームをメモリにロードし、起動する前に特定のメモリアドレスを変更して、無制限のライフ、無敵化、敵からの不可視化などのチートを行うことができた。このような変更は、POKEコマンドを使って行われた。コモドール64、ZX Spectrum、Amstrad CPCでは、関連するカートリッジやMultiface（英語版）を持っているプレイヤーは、実行中のプログラムをフリーズさせてPOKEを入力し、チート状態で再開することもできた。 例えば、ZX Spectrum向けの『ナイト・ロアー』では、以下のコマンドで無敵化することができた。 POKE 47196, 201 この場合、値201はRET命令に相当するので、衝突判定をトリガーする前に、ゲームがサブルーチンから早期に復帰する。 『ユア・シンクレア（英語版）』などの雑誌には、ゲームにおけるそのようなPOKEコマンドが掲載されていた。このようなコードは、一般的に、機械語コードをリバースエンジニアリングして、ライフ数、衝突の検出などに関連するメモリアドレスを識別することで発見されていた。 POKEによるチートの使用は、最近のゲームでは難しくなっている。最近のオペレーティングシステムは、外部プログラムからの非共有メモリへのアクセスができないようするために、仮想記憶化によるメモリ保護を行っている（例えば、アプリケーションごとにページテーブルを分けるなど）。 初期のBASICが動作するほとんどのコンピュータは8ビットプロセッサを使用していたため、1つのPEEKまたはPOKEの値は0から255の間のものだった。16ビットマシンにおいて16ビットの整数値を読み書きするには、PEEKやPOKEを2回実施する必要がある。アドレスAの16ビット整数値を読み出すためには、PEEK A+256*PEEK(A+1)とする必要があり、アドレスAに16ビット整数Vを書き込むためには、POKE A,(V AND 255)に続けてPOKE (A+1),TRUNC(V/256)を実行する必要がある。 IBM PCやAmigaなどの16・32ビットマシンでは、16ビット値を一度に読み書きできるDPEEKやDPOKEのようなコマンドが公式で用意されていた。Sinclair QLでは、16・32ビット値の読み書きができるPEEK_W/PEEK_L、POKE_W/POKE_Lコマンドがあった。Atari STシリーズでは、コマンド名称は8ビットのコマンドと同様だが、読み書きするビット幅を指定することができた。また、いくつかの8ビットマシンには、16ビット幅のPEEKとPOKEを行うBASIC方言があった。例えば、東ドイツの"Kleincomputer" KC85/1（別名 Z9001）やKC87には、DEEK、DOKEコマンドがあった。 1980年代初期のベンダーであるノーススター・コンピューターズは、独自のBASIC方言・North Star BASIC（英語版）を持つオペレーティングシステム・NSDOSを使用していたが、法的問題の懸念から、コマンド名をEXAMとFILLに変更していた。他に、MEMWとMEMRを代わりに使用するBASIC方言もあった。 BBC Microやその他のエイコーン・コンピュータのマシンで使用されたBBC BASIC（英語版）では、PEEKやPOKEというキーワードはなく、queryと呼ばれる疑問符(?)を関数とコマンドの両方の操作に使用していた。以下にその例を示す（以下の例では、分かりやすさのためにREMの後のコメント内の説明を日本語で表記しているが、実際のBBC BASICでは日本語は使えない）。 > DIM W% 4 : REM 4バイトのメモリを確保し、整数型変数 W% で指定する。 > ?W% = 42 : REM 定数 42 を格納する。これは'POKE W%, 42'と等価である。 > PRINT ?W% : REM W% が指すバイトを表示する。これは'PRINT PEEK(W%)'と等価である。 42 32ビット値は、plingと呼ばれる感嘆符(!)を使用して、最下位バイトを最初にして（リトルエンディアン）、PEEKやPOKEを実施することができる。さらに、アドレスの後にqueryかplingのいずれかを指定して、オフセット値を指定してアドレスをオフセットすることもできる。 > !W% = &12345678 : REM アンパサント(&)は16進数であることを意味する。 > PRINT ~?W%, ~W%?3 : REM チルダ(~)は16進数として表示する。 78 12 文字列は、ドル記号($)を使用して同様の方法でPEEKやPOKEを行うことができる。文字列の終端は、キャリッジリターン文字（ASCIIでは&0D）で示される。オフセットは、ドル記号では使用できない。 > DIM S% 20 : REM 20バイトのメモリを確保し、 S% で指定する。 > $S% = "MINCE PIES" : REM 文字列'MINCE PIES'を格納する。文字列は &0D で終端されている。 > PRINT $(S% + 6) : REM S% + 6バイトから始まる &0D で区切られた文字列を表示する。 PIES "POKE"という言葉は、特に1970年代後半から1980年代初頭にかけて8ビットコンピュータでプログラムを学んだ人々の間で、BASICを介したもの以外も含めて、「メモリの内容を直接操作すること」の意味で使用されることがある。 Visual Basic for Windowsでは、DDEを実現するのにLinkPokeキーワードを使用する。 8ビットビデオゲームのチートはPOKEと呼ばれることもあった（上記のチートとしてのPOKEを参照）。