web-dev-qa-db-ja.com

Cの画面メモリに書き込めません

私はCが初めてで、Javaに続く2番目の高水準プログラミング言語です。私はほとんどの基本を理解しましたが、何らかの理由でスクリーンメモリーに単一の文字を書き込むことができません。

このプログラムは、120MHzで動作するAm486-DX4-100でDOS用Turbo Cを使用してコンパイルされます。グラフィックカードは、Trio32チップを使用した非常に標準的なVLB Diamond Multimedia Stealth SEです。

OSの場合、ISOコードページがロードされたPC-DOS 2000を実行しています。色付きの標準MDA/CGA/EGA/VGAスタイル80カラムテキストモードで実行しています。

これが私が書いたプログラムです:

#include <stdio.h>

int main(void) {
    unsigned short int *Video = (unsigned short int *)0xB8000;
    *Video = 0x0402;
    getchar();
    return 0;
}

私が述べたように、私はCに非常に新しいので、私のエラーが明らかであるように思われる場合、私は理解することができるこれを行う方法に関する確固たる情報源を見つけることができませんでした。

私の知る限り、x86プラットフォームのリアルモードでは、テキストモードの画面メモリは0xB8000から始まります。各文字は2バイトで保存されます。1つは文字用で、もう1つは背景/前景用です。アイデアは、値0x0402(赤い笑顔のはず)を0xB8000に書き込むことです。これは、画面の左上に配置する必要があります。

私は、画面がスクロールする可能性を考慮して、2つの方法で実行時にすぐにキャラクターを削除しました。この問題を解決するために、私は試しました:

  • ループを使用してこの値を繰り返し書き込みます
  • さらに下に書きます。

メモリに書き込んだ値を読み取って印刷できるので、明らかにメモリのどこかに残っていますが、何らかの理由で画面には何も表示されません。私は明らかに何か間違ったことをしていますが、何が問題なのかわかりません。その他の詳細が必要な場合は、お問い合わせください。あなたが与えることができるあらゆる助けをありがとう。

43
Ampera

メモリの最初の完全な1MiBをアドレス指定するリアルモードでは、 20ビットセグメント:オフセット アドレス指定と呼ばれるメカニズムが使用されます。 0xb8000は物理メモリアドレスです。リアルモードセグメンテーションでメモリをアドレス指定できるfarポインターと呼ばれるものを使用する必要があります。さまざまなタイプのポインターについては、このセクションで説明します Stackoverflow Answer

0xb8000は、0xb800のセグメントと0x0000のオフセットとして表すことができます。物理アドレスを取得する計算は、セグメント* 16 +オフセットです。 0xb800 * 16 + 0x0000 = 0xb8000。これを念頭に置いて、dos.hおよびMK_FP[〜#〜] c [〜#〜]マクロは、セグメントとオフセットを指定して、そのようなアドレスへのfarポインターを初期化します。

documentation MK_FPは次のよ​​うに定義されています:

MK_FP()ファーポインターを作成する

#include   <dos.h>

void       far *MK_FP(seg,off);
unsigned   seg;                         Segment
unsigned   off;                         Offset

MK_FP()は、コンポーネントセグメント「seg」から「far」ポインタを作成し、「off」部分をオフセットするマクロです。

戻り値:ファーポインター。

コードは次のように書くことができます。

#include <stdio.h>
#include <dos.h>
int main(void) {
    unsigned short int far *Video = (unsigned short int far *)MK_FP(0xB800,0x0000);
    *Video = 0x0402;
    getchar();
    return 0;
}
55
Michael Petch

メモリセグメントアドレスは、使用されるビデオモードによって異なります。

0xA0000 for EGA/VGA graphics modes (64 KB)
0xB0000 for monochrome text mode (32 KB)
0xB8000 for color text mode and CGA-compatible graphics modes (32 KB)

Vramに直接アクセスするには、セグメントとオフセットアドレスを保持する32ビットポインターが必要です。そうしないと、ヒープが台無しになります。これは通常、未定義の動作につながります。

char far *Video = (char far *)0xb8000000;

参照: 近く、遠く、巨大なポインターは何ですか?

4
stacker

@stackerが指摘したように、16ビット環境では、ポインターを慎重に割り当てる必要があります。 FARキーワードを配置する必要があることを知っています(まあ、なんて懐かしい)。

また、いわゆる「巨大な」メモリモデルでコンパイルしないようにしてください。すべての32ビットポインターが自動的に20ビットに「正規化」されるため、これはファーアドレッシングとは互換性がありません。 「大」メモリモデルを選択してみてください。

2
valdo