[comp.sys.ibm.pc] Microsoft Quickc - Pointers to arbitrary memory location

dorl@vms.macc.wisc.edu (Michael Dorl - MACC) (09/01/88)

I've been trying to reference screen memory directly from Quickc.
The stuff I've tried looks something like this

  char far *p;
  long i;

  p = (char far *)0xb8000;
  for (i=0; i<0x8000; i++) {
   *p = '\000';
   p++;
  }

What i'm trying to do is blank out the screen on a Hercules card after
setting graph mode.  The manual for my machine says the graph memory is
at 0xb8000 and I've done similar things from GWBasic so I know they work.

When I run the above program, the PC hangs up.  I'm not even able to reboot
using ctrl-alt-del.

Questions:

  Is this kind of thing legal?

  If not, is there some other way to go about it?

  What should I set the pointer to so that *p referneces
  the right place?

Michael Dorl (608) 262-0466
dorl@vms.macc.wisc.edu
dorl@wiscmacc.bitnet

cdold@starfish.Convergent.COM (Clarence Dold) (09/02/88)

From article <666@dogie.edu>, by dorl@vms.macc.wisc.edu (Michael Dorl - MACC):
> I've been trying to reference screen memory directly from Quickc.
> The stuff I've tried looks something like this
> 
>   char far *p;
>   long i;
> 
>   p = (char far *)0xb8000; [...]
The problem is in the way that Microsoft chose to implement SEGMENT:OFFSET in
QuickC.  The address 0xb800:0000 should appear ax 0xb8000000.
This appears to be 32 bit addressing, but is actually SEGMENT followed by
OFFSET, with each being 16 bits, which will then be folded into the SEG:OFF
that the CPU wants to see.
This topic shows up in the SAMs book 'Microsoft C on the IBM PC'.
-- 
Clarence A Dold - cdold@starfish.Convergent.COM		(408) 435-5274
		...pyramid!ctnews!mitisft!professo!dold
		P.O.Box 6685, San Jose, CA 95150-6685

markd@proxftl.UUCP (Mark Davidson) (09/02/88)

In article <666@dogie.edu> dorl@vms.macc.wisc.edu (Michael Dorl - MACC) writes:
>I've been trying to reference screen memory directly from Quickc.
>The stuff I've tried looks something like this
>
>  char far *p;
>  long i;
>
>  p = (char far *)0xb8000;
>  for (i=0; i<0x8000; i++) {
>   *p = '\000';
>   p++;
>  }
(I hope this is right!)  One problem I see (at least it's different from the
way I tried it) is your assignment to p.  If your screen memory starts at
0xb8000 (this is an absolute address), then the value you assign to p must
be given in a variation of segment:offset format.  In other words, say

	p = (char far *) 0xb8000000;

and then dereference p to access a location in screen memory.  I've done this
in Quick C to implement pull-down menus, windows, etc (i.e., quick and dirty
prototyping).
-- 
  In real life: Mark E. Davidson       uflorida!novavax!proxftl!markd
  Proximity Technology Inc., 3511 NE 22nd Ave, Ft. Lauderdale FL, 33308
  #define STANDARD_DISCLAIMER          <Quote construction site>

mrh@camcon.co.uk (Mark Hughes) (09/08/88)

From article <666@dogie.edu>, by dorl@vms.macc.wisc.edu (Michael Dorl - MACC):
> I've been trying to reference screen memory directly from Quickc.
> The stuff I've tried looks something like this
> 
>   char far *p;
>   long i;
> 
>   p = (char far *)0xb8000;
>   for (i=0; i<0x8000; i++) {
>    *p = '\000';
>    p++;
>   }
> 
Try defining a macro like:-

#define fp(a) ( (( (long)(a) & 0xf0000 )<< 12) | ( (long(a) & 0xffff ) )

and replacing your pointer assignment with:-

p = (char far *)( fp( 0xb8000 ) );

The problem is caused by the way that pointers are stored, i.e. most
significant word contains segment address and l.s.w. contains the offset within 
the segment. Unfortunately, Microsoft C does not realise that you want to
point to the address 0xb8000, and simply interprets this as segment=0xb,
offset 0x8000. What you want is segment=0xb000, offset=0x8000. The macro
performs this conversion for you.

This is a consequence of the architecture of the 8086 (etc.), but I'm not sure
if the compiler should interpret your assignment in the way that it does.
Intuitively, I would say that the compiler should realise that you want to
point to a memory location and implement the assignment appropriately instead
of blindly stuffing the value into your variable.

Does anyone know what the standards say (if anything) about this?

-- 
-------------------  <mrh@camcon.co.uk>  or  <...!mcvax!ukc!idec!camcon!mrh>
|   Mark Hughes   |  Telex:   265871 (MONREF G) quoting: MAG70076
|(Compware . CCL) |  BT Gold: 72:MAG70076
-------------------  Teleph:  Cambridge (UK) (0)223-358855

kneller@cgl.ucsf.edu (Don Kneller) (09/13/88)

In article <1920@titan.camcon.co.uk> mrh@camcon.co.uk (Mark Hughes) writes:
>From article <666@dogie.edu>, by dorl@vms.macc.wisc.edu (Michael Dorl - MACC):
>> I've been trying to reference screen memory directly from Quickc.
>> The stuff I've tried looks something like this
>> 
>>   char far *p;
>> 
>>   p = (char far *)0xb8000;
>> 
>Try defining a macro like:-
>
>#define fp(a) ( (( (long)(a) & 0xf0000 )<< 12) | ( (long(a) & 0xffff ) )
>

MSC supplies the macros you need with FP_SEG and FP_OFF, which can be
used to get the segment and offset of far (32-bit) pointers.  They can
also be used to SET the segment and offset:

	FP_SEG(p) = 0xB800;
	FP_OFF(p) = 0;

and away you go with p[0], p[1], etc.  The macros are in dos.h.

- don
-----
	Don Kneller
UUCP:		...ucbvax!ucsfcgl!kneller
INTERNET:	kneller@cgl.ucsf.edu
BITNET:		kneller@ucsfcgl.BITNET