>Interestingly, FarWordPtr = *(word **__far)&BytePtr yields 0x7f7f80 instead of 0x7f80c0.
>(Why?)
Because I made a mistake.

Well, I said I did not try it out. Here's the fixed version (this time I compiled it):
#include <string.h>
unsigned char ptrData[3]= {0x7F, 0x80, 0xC0};
unsigned char *__far farPtr;
static void confUnion(void) {
union {
unsigned char* __far ptr;
unsigned char asBytes[3];
} u;
(void)memcpy(u.asBytes, ptrData, sizeof(u.asBytes));
farPtr= u.ptr;
}
static void confCast(void) {
farPtr= *(unsigned char *__far*)ptrData;
}
void main(void) {
confCast();
if (farPtr != (unsigned char *__far)0x7F80C0) {
for(;;) {/* bug */}
}
farPtr= 0;
confUnion();
if (farPtr != (unsigned char *__far)0x7F80C0) {
for(;;) {/* bug */}
}
for(;;) {}
}
As you can see, the __far was at the wrong indirection in my initial try, so the dereferenciation did only read 2 bytes.
Anyway, the byte per byte copy is simpler, so I prefer it. It's always good if one can easily see what is going on and this was the version which we both did get right in the first try. Keep it simple (so even I get it right

.
Using the union would also be a possible thing to do. Well not portable, but this problem is per definition not portable. So probably the union is even a bit cleaner as it clearly shows the reinterpretation of the values and it does not need any address casts at all.
Daniel
PS: It does not matter if you take the address of the array as I initially did. Probably its more clean to use the implicit conversion of the array to a pointer of its first field (its C...) One & less.