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, 2021 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, 2021 at 13:41
  • Changed to 16 but I still don't get the value I want in v.
    – Tomas By
    Apr 9, 2021 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, 2021 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, 2021 at 13:56

1 Answer 1


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, 2021 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, 2021 at 14:05
  • Okay that makes sense, I guess.
    – Tomas By
    Apr 9, 2021 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, 2021 at 15:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .