Cannot write to screen memory in C
In real mode to address the first full 1MiB of memory a mechanism called 20-bit segment:offset addressing is used. 0xb8000 is a physical memory address. You need to use something called a far
pointer that allows you to address memory with real mode segmentation. The different types of pointers are described in this Stackoverflow Answer
0xb8000 can be represented as a segment of 0xb800 and an offset of 0x0000. The calculation to get physical address is segment*16+offset. 0xb800*16+0x0000=0xb8000. With this in mind you can include dos.h
and use the MK_FP
C macro to initialize a far
pointer to such an address given segment and offset.
From the documentation MK_FP is defined as:
MK_FP() Make a Far Pointer
#include <dos.h> void far *MK_FP(seg,off); unsigned seg; Segment unsigned off; Offset
MK_FP() is a macro that makes a far pointer from its component segment 'seg' and offset 'off' parts.
Returns: A far pointer.
Your code could be written like this:
#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;
}
As @stacker pointed-out, in the 16-bit environment you need to assign the pointer carefully. AFAIK you need to put FAR
keyword (my gosh, what a nostalgia).
Also make sure you don't compile in so-called "Huge" memory model. It's incompatible with far addressing, because every 32-bit pointer is automatically "normalized" to 20 bits. Try selecting "Large" memory model.
The memory segment adress depends on the video mode used:
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)
To directly access vram you need a 32 bit-pointer to hold segement and offset address otherwise you would mess up your heap. This usually leads to undefined behaviour.
char far *Video = (char far *)0xb8000000;
See also: What are near, far and huge pointers?