[comp.sys.ibm.pc] Turbo C far pointers

elrond@titan.tsd.arlut.utexas.edu (Brad Hlista) (10/28/89)

I am having a problem of getting an allocated block of far memory
to return float values.  Here is how variables are declared and dereferenced:

far *ptr;

main()
{
int i;

	ptr=(float *) farmalloc(100000);

	f(i=0;i<1000;i++)
		*(ptr+i)=3.1415927;

	for(i=0;i<10;i++)
		printf(" %f", (float) *(ptr+i) ) ;  /* is yielding 3.00000 */
}

Can someone please help me understand what is going on?
Thanks.

Brad
elrond@titan.tsd.arlut.utexas.edu
   

jwright@atanasoff.cs.iastate.edu (Jim Wright) (10/29/89)

In a recent posting elrond@titan.tsd.arlut.utexas.edu (Brad Hlista) writes:
| I am having a problem of getting an allocated block of far memory
| to return float values.  Here is how variables are declared and dereferenced:

| far *ptr;

I think this is the big part.  An int pointer is not the same as a float
pointer.  The following program works for me (MSC).

#include <stdio.h>
#include <malloc.h>
int main(void);

int main()
{
    int i;
    float far *start;
    float far *p;

    start = (float far *) _fmalloc(1000*sizeof(float));

    if (start != NULL) {
        printf("Good.\n");
        for (p=start,i=0 ; i<1000 ; i++)
            *(p++) = 3.1415927;
        for (p=start,i=0 ; i<10 ; i++)
            printf("%f\n", *(p++));
    }
    else
        printf("Oh shit.\n");
    return(0);
}

-- 
Jim Wright
jwright@atanasoff.cs.iastate.edu

bdb@becker.UUCP (Bruce Becker) (10/29/89)

In article <565@titan.tsd.arlut.utexas.edu> elrond@titan.tsd.arlut.utexas.edu (Brad Hlista) writes:
|I am having a problem of getting an allocated block of far memory
|to return float values.  Here is how variables are declared and dereferenced:
|
|far *ptr;
|
|main()
|{
|int i;
|
|	ptr=(float *) farmalloc(100000);
|
|	f(i=0;i<1000;i++)
|		*(ptr+i)=3.1415927;

Should be:	*((float *)(ptr+i)) = 3.1415927;

	Otherwise the "far" declaration of "ptr"
	will force a type conversion to the default
	of type "int". The way you have it the
	contents of of *(ptr+i)" contains an int
	value which is coerced back to float
	in the printf statement.

|	for(i=0;i<10;i++)
|		printf(" %f", (float) *(ptr+i) ) ;  /* is yielding 3.00000 */

Should be	printf(" %f", *((float *)(ptr+i)) ) ;  /* is yielding 3.1415927 */

|}
|
|Can someone please help me understand what is going on?
|Thanks.

	You need to ensure that either by default
	or by explicit declaration that
	sizeof(far) == sizeof(float); is there a
	"far long" type? Better yet, a "far float"?

	I didn't actually try this so if your compiler
	barfs on "*((float *)ptr)" where "ptr" is a
	"far *" declaration, well... you could try
	"far float * ptr;", etc...

Cheers,
-- 
  .::.	 Bruce Becker	Toronto, Ont.
w \@@/	 Internet: bdb@becker.UUCP, bruce@gpu.utcs.toronto.edu
 `/c/-e	 BitNet:   BECKER@HUMBER.BITNET
_/  \_	 In the future the term "wife" will have no gender significance

CMH117@PSUVM.BITNET (Charles Hannum) (10/29/89)

Two suggestions:

  1)  Your main problem is that you need to use the declaration:

      far float *ptr;

      I won't even try to explain what happens otherwise.

  2)  You really should use "ptr[i]" rather than "*(ptr+i)".  It effectively
      does the same thing, but it makes for much cleaner and much more
      readable code.

hp0p+@andrew.cmu.edu (Hokkun Pang) (10/31/89)

>  2)  You really should use "ptr[i]" rather than "*(ptr+i)".  It effectively
>      does the same thing, but it makes for much cleaner and much more
>      readable code.

I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?

spolsky-joel@CS.YALE.EDU (Joel Spolsky) (10/31/89)

In article <wZHEDrW00VoH479lIM@andrew.cmu.edu> hp0p+@andrew.cmu.edu (Hokkun Pang) writes:
>>  2)  You really should use "ptr[i]" rather than "*(ptr+i)".  It effectively
>>      does the same thing, but it makes for much cleaner and much more
>>      readable code.
>
>I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
>compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?


That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same
code. There is no reason to believe that the compiler prefers one over
the other, or that the compiler implements A[1] by first expanding
that to *(A+1). For all you know it does the opposite. 

And even if it did make a difference, it would be so small as to be
imperceivable even on the worlds slowest C compiler running on an
HP-41C. 

+----------------+----------------------------------------------------------+
|  Joel Spolsky  | bitnet: spolsky@yalecs.bitnet     uucp: ...!yale!spolsky |
|                | internet: spolsky@cs.yale.edu     voicenet: 203-436-1538 |
+----------------+----------------------------------------------------------+
                                                      #include <disclaimer.h>

levitte@garbo.bion.kth.se (Tommy Levitte) (10/31/89)

In article <990@becker.UUCP> bdb@becker.UUCP (Bruce Becker) writes:
Bruce> Xref: sics.se alt.msdos.programmer:153 comp.sys.ibm.pc:29919

Bruce> In article <565@titan.tsd.arlut.utexas.edu> elrond@titan.tsd.arlut.utexas.edu (Brad Hlista) writes:

Bruce> |far *ptr;

Bruce> |main()

[... unimportant things deleted ...]

Bruce> |	f(i=0;i<1000;i++)
Bruce> |		*(ptr+i)=3.1415927;

Bruce> Should be:	*((float *)(ptr+i)) = 3.1415927;

(* GAACK *) This means you should use the i'th INTEGER location, not float!
Wow. The effect when printing out would be quite a sight...

No, the correct syntax would be : *((float *)ptr + i)

This way, you tell the compiler that ptr really is a float pointer, then
offset the whole thing with i.

In your solution, the offset would be 2*i bytes (2 = sizeof(int)). In mine,
the offset would be 4*i bytes (4=sizeof(float)) !!!!

Bruce> |	for(i=0;i<10;i++)
Bruce> |		printf(" %f", (float) *(ptr+i) ) ;  /* is yielding 3.00000 */

Bruce> Should be	printf(" %f", *((float *)(ptr+i)) ) ;  /* is yielding 3.1415927 */

Likewise here. Use *((float)ptr + i) instead !

Bruce> 	sizeof(far) == sizeof(float); is there a
Bruce> 	"far long" type? Better yet, a "far float"?

Wow. sizeof(far) ! Never seen that before. This would mean 'far int', which is
not (as far as I know) permitted in TC.
far is only applied on pointer and functions, to tell the compiler you need a
4-byte adress to get those objects. Thus, far is a modifier, not a type.
Now, about int. int is the same as short in TC, a 2-byte integer. float is a
4-byte float.

One IMPORTANT rule when you program in C: NEVER assume anything about the size
of differnet types. NEVER !!!!!

Bruce> 	I didn't actually try this so if your compiler
Bruce> 	barfs on "*((float *)ptr)" where "ptr" is a
Bruce> 	"far *" declaration, well... you could try
Bruce> 	"far float * ptr;", etc...

Quite surprising. I just tried it with Turbo C v 2.0, writing 
*((float *)ptr+i), and it worked just nice. writing *((float *)(ptr+i)) gave
me 0.000000 when I tried it...


--
Tommy Levitte 
	gizmo@nada.kth.se
	gizmo@kicki.stacken.kth.se
	gizmo@ttt.kth.se

hollen@eta.megatek.uucp (Dion Hollenbeck) (11/01/89)

From article <990@becker.UUCP>, by bdb@becker.UUCP (Bruce Becker):
> In article <565@titan.tsd.arlut.utexas.edu> elrond@titan.tsd.arlut.utexas.edu (Brad Hlista) writes:
> |I am having a problem of getting an allocated block of far memory
> |to return float values.  Here is how variables are declared and dereferenced:
> |
> |far *ptr;
> |
> |main()
> |{
> |int i;
> |
> |	ptr=(float *) farmalloc(100000);
> |
> |	f(i=0;i<1000;i++)
> |		*(ptr+i)=3.1415927;
> 
> Should be:	*((float *)(ptr+i)) = 3.1415927;
> 
> 	Otherwise the "far" declaration of "ptr"
> 	will force a type conversion to the default
> 	of type "int".

If the pointer is declared to be of type "float far *" then the
statement  "ptr + i" says "ptr + sizeof(type of ptr)*i" even
though i is an int.  If this does not occur, then the compiler
is broken.  The program could be written thusly:

main()
{
	float far *ptr;

	ptr = (float *) farmalloc(100000);

	f(i=0;i<1000;i++)
		*(ptr+i)=3.1415927;

}

The key is to declare the pointer to be a far ptr to a type of float
and incrementation and pointer arithmetic will work.

	Dion Hollenbeck             (619) 455-5590 x2814
	Megatek Corporation, 9645 Scranton Road, San Diego, CA  92121

        uunet!megatek!hollen       or  hollen@megatek.uucp

c9h@psuecl.bitnet (11/01/89)

In article <4037@cs.yale.edu>, spolsky-joel@CS.YALE.EDU (Joel Spolsky) writes:
> In article <wZHEDrW00VoH479lIM@andrew.cmu.edu> hp0p+@andrew.cmu.edu (Hokkun Pang) writes:
>>>  2)  You really should use "ptr[i]" rather than "*(ptr+i)".  It effectively
>>>      does the same thing, but it makes for much cleaner and much more
>>>      readable code.
>>
>>I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
>>compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?
>
>
> That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same
> code. There is no reason to believe that the compiler prefers one over
> the other, or that the compiler implements A[1] by first expanding
> that to *(A+1). For all you know it does the opposite.
>
> And even if it did make a difference, it would be so small as to be
> imperceivable even on the worlds slowest C compiler running on an
> HP-41C.

point is that "ptr[i]" makes more sense to the average person than "*(ptr+i)",
and will, in fact, produce *exactly* the same code.

And it most certainly WILL NOT produce the same code as "(*ptr)+i"!  IF
your compiler does this, then it is VERY non-standard.

BTW:  How long it takes the compiler to resolve an expression has very
      little to do with execution speed.

Anyway, this has turned into an argument about semantics, and if anywhere,
that should be constrained to comp.lang.c.


- Charles Hannum        |  Klein bottle for sale ...  |  Live long and prosper.
  c9h@psuecl.psu.edu    |  inquire within.            |
  cmh117@psuvm.psu.edu  |                             |  To life immortal!

dbin@norsat.UUCP (Dave Binette) (11/01/89)

In article <wZHEDrW00VoH479lIM@andrew.cmu.edu> hp0p+@andrew.cmu.edu (Hokkun Pang) writes:
>I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
>compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?

Its possible but not alwyays determinable.  In fact it may depend on the
compiler and the native CPU.

Some CPU's handle array indexing more efficiently than pointers so in either
case your kind of at the mercy of those who ported the compiler to your
machine.
-- 
OS2... The nightmare continues.
uucp:  {uunet,ubc-cs}!van-bc!norsat!dbin | 302-12886 78th Ave
bbs:   (604)597-4361     24/12/PEP/3     | Surrey BC CANADA
voice: (604)597-6298     (Dave Binette)  | V3W 8E7

johnl@esegue.segue.boston.ma.us (John R. Levine) (11/02/89)

In article <150@norsat.UUCP> dbin@norsat.UUCP (Dave Binette) writes:
>In article <wZHEDrW00VoH479lIM@andrew.cmu.edu> hp0p+@andrew.cmu.edu (Hokkun Pang) writes:
>>I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
>>compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?
>...
>Some CPU's handle array indexing more efficiently than pointers so in either
>case your [sic] kind of at the mercy of those who ported the compiler to your
>machine.

Sheesh.  The two expressions are defined by the language to mean exactly the
same thing.  Anywhere you can use one of them, you can use the other and get
exactly the same result.  A C compiler should generate exactly the same code
for both.

In practice, every C compiler that I have seen converts ptr[i] to *(ptr+i) at
compile time, and then generates the code.  (Well, actually, I once did see a
compiler that generated different code, but it turned out to be a mutant PL/I
compiler rather than a C compiler.) I suppose there might be some microscopic
difference in compile speed between the two, but the runtime performance that
most people worry about will be identical.

This is one of the most frequently misunderstood parts of the C language.  If
you still aren't sure why the two expressions are equivalent, this would be a
good time to go back and reread your C books.
-- 
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl@esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
Massachusetts has over 100,000 unlicensed drivers.  -The Globe

2179ak@gmuvax2.gmu.edu (JDPorter) (11/16/89)

In article <4037@cs.yale.edu> spolsky-joel@CS.YALE.EDU (Joel Spolsky) writes:
>In article <wZHEDrW00VoH479lIM@andrew.cmu.edu> hp0p+@andrew.cmu.edu (Hokkun Pang) writes:
>>I read from a book that "ptr[i]" will be converted to "*(ptr+i)" by the
>>compiler, so the "*(ptr+1)" is faster than "ptr[1]". Is that right?
>That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same
>code. There is no reason to believe that the compiler prefers one over

Sorry, I must disagree. (item #0: '1[A]' looks very alien and undigestible
to me.)
But to get to the point:
*(A+1) does NOT produce the same code as A[1].  (not for MSC, anyway.)
The first form takes the pointer, increments it by one (as a pointer 
entity), and dereferences it.
The second form places the specified index into an index register (or
offset register, if you prefer) and dereferences the pointer PLUS the
offset.  
In general, the SECOND form executes in FEWER cycles (contrary to the
C programmer's notion that pointers are always the most efficient.)

John Porter

johnl@esegue.segue.boston.ma.us (John R. Levine) (11/16/89)

In article <579@gmuvax2.gmu.edu> 2179ak@gmuvax2.UUCP (JDPorter) writes:
>>That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same code.

>*(A+1) does NOT produce the same code as A[1].  (not for MSC, anyway.)

Congratulations, you've found an optimization bug in MSC.  In Turbo, assuming
that A is an int * passed as an argument, they all generate these two
instructions (picked verbatim from the generated .ASM):

	mov	bx,word ptr [bp+4]
	mov	ax,word ptr [bx+2]

Can we stop arguing about this now?
-- 
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl@esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
"Now, we are all jelly doughnuts."

alanf@bruce.OZ (Alan Grant Finlay) (11/17/89)

In Article <6689@esegue.segue.boston.ma.us> John R. Levine writes:

>In article <579@gmuvax2.gmu.edu> 2179ak@gmuvax2.UUCP (JDPorter) writes:
>>>>That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same code.
>
>>*(A+1) does NOT produce the same code as A[1].  (not for MSC, anyway.)
>
>Congratulations, you've found an optimization bug in MSC.  In Turbo, assuming

As I am doing research in programming language semantics I can't resist putting
my oar in.  This is an issue I have much meditated upon in the past.  As I see
it the semantics of high level programming languages are best left independent
of efficiency specifications.  This is partly due to the need for machine
independence but also for more philosophical reasons.  With high level languages
the programmer wants to be able to say what is to be done without being
concerned about how it is done.  With assembly languages the reverse is the
case (i.e. if you can't do what you want efficiently then you change the
requirements).  Hence for high level languages we have optimisation of the 
generated code.  I have never heard of an optimiser intended for hand written
assembly code (except maybe rumours from the AI community).

This brings me to the problem child C which has characteristics of both
high and low level languages.  C is undoubtably a popular language much to
my disgust.  If C replaces COBOL we will be no better off.  There, I've said
it, and will probably never live it down.  More seriously though what does
"Kernighan and Ritchie" say?  Page 94 (1978 edition): 

   "Rather more surprising, at least at first sight, is the fact that a
    reference to a[i] can also be written as *(a+i).  In evaluating a[i],
    C converts it to *(a+i) immediately; the two forms are completely
    equivalent."

Although the meaning of "equivalent" is not further specified we are given
the additional clue that a conversion on a syntactic level can be presumed
to have taken place.  A similar discussion in the appendix page 210 states:

   "By definition, the subscript operator [] is interpreted in such a
    way that E1[E2] is identical to *((E1)+(E2)).  Because of the
    conversion rules which apply to +, if E1 is an array and E2 an 
    integer, then E1[E2] refers to the E2-th member of E1.  Therefore
    despite its asymmetric appearance, subscripting is a commutative
    operation."

From the tone of the discussion I draw the following conclusions:

1) The equivalence referred to is "equivalence in effect" and does not
   dictate the means by which this effect is produced.  The language 
   manual occasionally refers to machine dependencies but hardly
   presumes to dictate the code generated.  In fact it states that:
   (page 212) "Some difficulties arise only when dubious coding 
   practices are used.  It is exceedingly unwise to write programs 
   which depend on any of these properties."

2) The C language assumes it is implemented on a certain class of machine 
   which we may broadly classify as "Von Neumann" or perhaps more accurately
   as "linear addressable data and code".  We may not presume that
   the instruction set architecture has index registers.  Some form of
   indirect addressing must be achievable. 

I think to assume that source code which is equivalent "by definition"
must generate the same (essentially) object code in a single code object,
is a dubious coding practice.  Although the C language is clearly defined
for efficient programming on a certain class of machine there are no
guarantees written into the language definition that such and such a way of
doing something will be more efficient than any other way.

C lovers please post your flames to "comp.lang.c" which I agree to read
for the next few weeks.

bl@infovax.UUCP (Bj|rn Larsson) (11/19/89)

In article <1697@bruce.OZ> alanf@bruce.OZ (Alan Grant Finlay) writes:
>
>In Article <6689@esegue.segue.boston.ma.us> John R. Levine writes:
>
>>In article <579@gmuvax2.gmu.edu> 2179ak@gmuvax2.UUCP (JDPorter) writes:
>>>>>That's ridiculous. *(A+1), A[1], and 1[A] all produce exactly the same code.
>>
>>>*(A+1) does NOT produce the same code as A[1].  (not for MSC, anyway.)
>>
>>Congratulations, you've found an optimization bug in MSC.  In Turbo, assuming
>
>As I am doing research in programming language semantics I can't resist putting
>my oar in.  This is an issue I have much meditated upon in the past.  As I see
>it the semantics of high level programming languages are best left independent
>of efficiency specifications.  This is partly due to the need for machine
>independence but also for more philosophical reasons.  With high level languages

I have not read the original article or most of the followups but as I
see it, it is best to use the syntax

	A[i]

to access an array element if A is actually an array which is accessed
directly, and

	*(A+i)

if you access an array element via a pointer (A in this case) which points
to the start of the array. In other words, in the first example, A is the
ARRAY ITSELF - in the second, A is a POINTER TO the array. To me, any
other practice is MISLEADING as to what is really going on in the hardware,
although the same effects are achieved. To me it is actually somewhat
unfortunate that C allows this kind of 'aliasing' for fundamentaly diffe-
rent access methods. The example

	i[A]

mentioned above should NOT work. in fact it is awful!  The compiler would
have to assume that i is a pointer, but of which type?  Except this being
a syntax error, the compiler needs to know the size of the element type
that i points to, so it knows how much to multiply A (which is also not
an integer type) to yield the offset in BYTES from where i points... YUCK!!!
Still, this might actually work on machines that have the same size of
integers and pointers... and a very forgiving compiler indeed.

This is also the area where 'C' programmers who don't know assembly
language make the most mistakes. Sometimes you can see horrible errors
being made, and when one tries to explain why it is an error, they don't
understand - they just don't have the concept of 'primary memory' which
you can either write into directly or access indirectly via pointers.

Note I don't discuss optimizer efficiency above. But why would you expect
a compiler to actually generate the exact same code if the source code
is different. Wouldn't it be possible that an optimizer WILL find other
optimizations methods (based on the surrounding statements) if the source
code is different? The important thing must be that if you give a function
some input, you get the correct output, independent of the algorithm and
coding practices.

To rely on the knowledge of how one specific compiler generates code I
consider bad practice - your assumptions will not hold if you port to
another compiler/environment. Of course, I'm stretching my point somewhat
here - you usually code in a way that is generally efficient - but be
aware that there may be machine architectures where 'normally efficient'
coding practices are LESS efficient. For example, often DSP's (signal
processors) need to be coded in a very different way, since they
allow a greater degree of parallell data transfering and instruction
pipe-lining, and 'normal' coding will not make use of these possible
advantages.

Furthermore, the speed differencies caused by different optimizations
will probably be extremly minor. Usually, if you use code size optimi-
zation with MSC or Turbo C (all versions) you'll only save a few hund-
red bytes in a typical 32k program. When I have tried speed optimization,
it usually hasn't even been possible to measure any resulting improvements
when executing the code, although the machine code WAS indeed different
(but alas, not faster). Note: this is my experience for PC's - I think
under UNIX you will probably get a measurable improvement by using the
optimization flags (5-10% maybe?). Just don't expect miraculous bene-
fits!
-- 
 ====================== InfoVox = Speech Technology =======================
 Bjorn Larsson, INFOVOX AB      :      ...seismo!mcvax!kth!sunic!infovax!bl
 Box 2503                       :         bl@infovox.se
 S-171 02 Solna, Sweden         :         Phone (+46) 8 735 80 90