Trying to access one byte in memory using segment/offset, like this

union REGS in, out;
struct SEGS segs;
int v;
char _far* p;
p = (segs.es << 16) + out.x.bx + 4;
v = (int)*p;

and get "warning C4047: different levels of indirection" (and the value of v does not seem to be correct).

What am I doing wrong?

More info: at location p there is an eight byte struct, and I want the fifth byte only.

  • To start with,I guess you either want to shift ES by 4 to calculate a real mode address (aka a huge pointer), or 16 do store it into the segment portion of the pointer (as it's a far pointer). I might go with the later.
    – Raffzahn
    Apr 9 at 13:37
  • Okay... I saw that somewhere but one nice looking page said one byte so I went with that. Also, what about the indirection?
    – Tomas By
    Apr 9 at 13:41
  • Changed to 16 but I still don't get the value I want in v.
    – Tomas By
    Apr 9 at 13:43
  • 1
    Some compilers helpfully provide a MK_FP macro to construct a far pointer with the correct shift. This thread in comp.os.msdos.programmer gives some suggestions for how to implement it in Microsoft C: groups.google.com/g/comp.os.msdos.programmer/c/zUC_3ZLs_Hs
    – john_e
    Apr 9 at 13:48
  • 1
    I'm the machine guy - for C wizz you might want to look at SE. Also, the Q misses an information which line is the offending one? Is it when construction the pointer or using it?
    – Raffzahn
    Apr 9 at 13:56

Compilers targeting DOS typically provide macros to manipulate the segment and offset of far pointers. FP_SEG(pointer) provides access to the segment portion, FP_OFF(pointer) to the offset. It's also possible that there's a MK_FP(segment, offset) or FP_CONSTRUCT(segment, offset) macro to combine segment and offset into a pointer.

This discussion in comp.os.msdos.programmer suggests that for Microsoft C, a solution would be to assign using FP_SEG and FP_OFF:

FP_SEG(pointer) = segment;
FP_OFF(pointer) = offset;

Further down there is a possible definition of MK_FP, in case Microsoft C doesn't provide it:

#if !defined(MK_FP)
#define MK_FP(seg,ofs) ((void far *)(((unsigned long)(seg) << 16) | (ofs)))

This would then allow you to use

pointer = MK_FP(segment, offset);
  • So... is it multiply by 16 or shift by 16? Considering it is two 16-bit values to begin with, shift 16 does not seem quite right.
    – Tomas By
    Apr 9 at 14:01
  • 3
    It's common for compilers to store segment and offset of a far pointer in the high and low words of a 32-bit doubleword. This is likely what Microsoft C is doing.
    – john_e
    Apr 9 at 14:05
  • Okay that makes sense, I guess.
    – Tomas By
    Apr 9 at 14:06
  • @TomasBy It depends what you're looking for /trying to construct. A far pointer is a segment/offset pair stored in two consecutive 16 bit words (keep in mind, the 8086 is a strict 16 bit machine, no 32 bit), one for segment one for offset. As such it's portable between real mode and (286) protected mode. To pack two 16 bit into a 32 bit, one (the segment) needs to be shifted by 16 places. A huge pointer is a 20 (or more) bit value hold holding the effective (real) memory address. For 8086 it is constructed by multiplying the segment by 16 (shifting by four) and adding the offset.
    – Raffzahn
    Apr 9 at 15:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.