[net.micro.68k] Question of Ignorance

dsi@unccvax.UUCP (Dataspan Inc) (05/08/85)

    Pardon my excess stupididy, but I have a question about the
** CORRECT ** way a C-compiler (by definition) should handle the
following program. Consider main.c, below


/*
 * main.c
 */
char *charptr; 
short *shortptr;
int  *intptr; 
long *longptr;
main()
{
if(charptr == 32); 
if(intptr == 32)  ;
if(longptr== 32) ;
if(shortptr == 32 );
}
/*
 * end main.c 
 */

   This is the assembly language that my VAX 4.2bsd included-in-the-
distribution C-compiler takes care of main.c:

LL0:
	.data
	.comm	_charptr,4
	.comm	_shortptr,4
	.comm	_intptr,4
	.comm	_longptr,4
	.text
	.align	1
	.globl	_main
_main:
	.word	L16
	jbr 	L18
L19:
	cmpl	_charptr,$32
	jneq	L20
L20:
	cmpl	_intptr,$32
	jneq	L21
L21:
	cmpl	_longptr,$32
	jneq	L22
L22:
	cmpl	_shortptr,$32
	jneq	L23
L23:
	ret
	.set	L16,0x0
L18:
	jbr 	L19
	.data


    And * THIS * is the way the Alcyon C-compiler handles it:


.globl _charptr
.comm _charptr,4
.globl _shortptr
.comm _shortptr,4
.globl _intptr
.comm _intptr,4
.globl _longptr
.comm _longptr,4
.globl _main
.text
_main:
~~main:
~_EnD__=8
link R14,#-4
*line 8
*line 8
cmp.l #32,_charptr
bne L2
L2:
*line 9
*line 9
cmp.l #64,_intptr
bne L3
L3:
*line 10
*line 10
cmp.l #128,_longptr
bne L4
L4:
*line 11
*line 11
cmp.l #64,_shortptr
bne L5
L5:
L1:
unlk R14
rts
.data

    Note that the Alcyon compiler leaves the constant alone if the
thing is a char; shifts it left one if it is an int (2 bytes), and
left two if it is a long (4 bytes).

     Bill Allen at Alcyon Corporation assures me that this is not
a bug, that constants MUST BE MULTIPLIED BY THE NUMBER OF BYTES
when doing a test with a pointer. He even swears that the regular
C compiler cc must do this.

    When you are doing a proprietary product, it is sometimes nice
to do stupid things like mixing types in an if() and having things
be handled intelligently. Of course, you can do something like:

long *longptr;
long templong;
main()
{
    .    
    . 
    templong = longptr;
    if (templong == 32) ; /* do something nerdy */
    .
    .
}

   but this is just as bad as doing what you (thought?) you wanted
inside the if, anyway (??).

    Jim Wiley, an associate, thinks that the Alcyon confuses 
alignment problem with

    longptr = longptr + 32;

    which of course means 32 boundaries, i.e. 128 would be the
immediate operand.

   I'm really ignorant about C-language with this particular problem,
and would greatly appreciate comments on these hypothetical
programs and their .asm files.

-dya-

PS: If you have an oddball compiler, a listing generated from the
first main() above would be interesting...

PSS: The Whitesmiths handles it "correctly" (the immediate operand
to cmpi.l is #32 in every case)


David Anthony
Senior Analog Nut
DataSpan, Inc.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (05/10/85)

Alcyon is all wet.  If they support comparison of pointers with
integers, they should convert one to the other type before
comparison, which does NOT involve multiplying anything by
sizeof (*pointer).  However, officially the only integer you
are allowed to compare against a pointer is the constant 0.

keesan@bbncca.ARPA (Morris M. Keesan) (05/10/85)

------------------------------
>    Pardon my excess stupididy, but I have a question about the
>** CORRECT ** way a C-compiler (by definition) should handle the
>following program. Consider main.c, below
>long *longptr;
>main()
>{
>if(longptr== 32) ;
>}
 . . . code examples . . .
>    Note that the Alcyon compiler leaves the constant alone if the
>thing is a char; shifts it left one if it is an int (2 bytes), and
>left two if it is a long (4 bytes).
>
>     Bill Allen at Alcyon Corporation assures me that this is not
>a bug, that constants MUST BE MULTIPLIED BY THE NUMBER OF BYTES
>when doing a test with a pointer. He even swears that the regular
>C compiler cc must do this.
>
>Of course, you can do something like:

>long *longptr;
>long templong;
>main()
>{
>    templong = longptr;
>    if (templong == 32) ; /* do something nerdy */
>}
>
>David Anthony
>Senior Analog Nut
>DataSpan, Inc.
---------------------
    From The C Reference Manual, section "7.7 Equality Operators" (page 190 of
K&R): "A pointer may be compared to an integer, but the result is machine
dependent unless the integer is the constant 0."  This means that by definition
a C compiler is free to do what it wants in this case.  Personally, I think that
Alcyon is confused, but their compiler is behaving in a legal way.  My guess
is that it's easiest for them to treat all operations between pointers and
integers the same way, and so they do the same scaling for + and ==.
    Because of the undefined behaviour of ptr == int, and because some newer C
compilers don't allow the operation at all (my latest draft copy of the ANSI 
standard doesn't allow it), I recommend using one of the two constructs

    ( longptr == (long *)32 )
or  ( (int)longptr == 32 )

which are guaranteed to do what you want (the cast is equivalent to assigning
to a temporary of the right type, and the assignment is defined as "with no
conversion").  Note that the second case is equivalent to your workaround of
"templong = longptr; if( templong == 32);", but without the extra assignment.
-- 
Morris M. Keesan
{decvax,linus,ihnp4,wanginst,wjh12,ima}!bbncca!keesan
keesan @ BBN-UNIX.ARPA

alan@oscvax.UUCP (Alan Rooks) (05/12/85)

David Anthony was wondering why Alcyon Corp's C compiler scales constants in:

if (ptr == CONSTANT) ...

Maybe Alcyon's justification for this is that (they think) it is equivalent to:

if (ptr - CONSTANT == 0) ...

which is generally true in comparisons, but not with pointers. So when they
subtract the constant from the pointer, they have to scale it, as per
K&R page 189. The funny thing is, they don't generate code with a subtraction
and a compare against zero (and it would be a shame if they did) ...

Alan Rooks, Ontario Science Centre

henry@utzoo.UUCP (Henry Spencer) (05/12/85)

> ... I recommend using one of the two constructs
> 
>     ( longptr == (long *)32 )
> or  ( (int)longptr == 32 )
> 
> which are guaranteed to do what you want ...

Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
have no guarantees that an int is long enough to hold a pointer.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

throopw@rtp47.UUCP (Wayne Throop) (05/13/85)

In article <5590@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
>> ... I recommend using one of the two constructs
>> 
>>     ( longptr == (long *)32 )
>> or  ( (int)longptr == 32 )
>> 
>> which are guaranteed to do what you want ...
>
>Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
>have no guarantees that an int is long enough to hold a pointer.

I'm not sure what ANSI C says about pointers fitting into longs, but I
don't think there is any guarantee there either.  If there IS such a
guarantee, It doesn't seem like a good idea, since I know of 
machines upon which pointers don't even fit in longs.  Of course, 
pointers would have a better *chance* of fitting into a long :-).
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!rtp47!throopw

yamauchi@fortune.UUCP (Alan Yamauchi) (05/14/85)

Why is this appropriate to net.micro.68k?  Please keep your C
questions and replies for that matter out of this newsgroup!

ken@turtlevax.UUCP (Ken Turkowski) (05/14/85)

In article <5590@utzoo.UUCP> henry@utzoo.UUCP (Henry Spencer) writes:
> > ... I recommend using one of the two constructs
> > 
> >     ( longptr == (long *)32 )
> > or  ( (int)longptr == 32 )
> > 
> > which are guaranteed to do what you want ...
>
>Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
>have no guarantees that an int is long enough to hold a pointer.

Arghh!  Wrong again.  You can't cast an lvalue, so that the second option
is not available.  You MUST say		longptr = (long *)32;
-- 

Ken Turkowski @ CADLINC, Menlo Park, CA
UUCP: {amd,decwrl,hplabs,nsc,seismo,spar}!turtlevax!ken
ARPA: turtlevax!ken@DECWRL.ARPA

keesan@bbnccv.UUCP (Morris M. Keesan) (05/15/85)

--------------------------------------------------------------------
> > ... I recommend using one of the two constructs
> > 
> >     ( longptr == (long *)32 )
> > or  ( (int)longptr == 32 )
> > 
> > which are guaranteed to do what you want ...
> 
> Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
> have no guarantees that an int is long enough to hold a pointer.

Nor do you have any guarantees that a long is enough to hold a pointer.  I
was thinking that the (int) cast was sufficient because 32 is an int, but on
reflection I see that it might truncate longptr and give a result of TRUE if
the low-order int of longptr were 32.  I hereby retract my recommendation of
the second form, but stand by the first, which was my preference anyway.
---------------------------------
Morris M. Keesan
{decvax,ihnp4,etc.}!bbncca!keesan
keesan@bbn-unix.ARPA

keesan@bbnccv.UUCP (Morris M. Keesan) (05/15/85)

------------------------------------------------------------------------
> > > ... I recommend using one of the two constructs
> > > 
> > >     ( longptr == (long *)32 )
> > > or  ( (int)longptr == 32 )
> > > 
> > > which are guaranteed to do what you want ...
> >
> >Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
> >have no guarantees that an int is long enough to hold a pointer.
> 
> Arghh!  Wrong again.  You can't cast an lvalue, so that the second option
> is not available.  You MUST say		longptr = (long *)32;
----------------------------------------
HUH?  Of course you can cast an lvalue.  It's just not an lvalue when you get
through casting it.  You're confusing == (equality operator, which is what we
were discussing) with = (assignment operator, which is what you're discussing).
-----------------
Morris M. Keesan
{ihnp4,decvax,etc.}!bbncca!keesan
keesan@bbn-unix.ARPA

roy@phri.UUCP (Roy Smith) (05/16/85)

> >Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
> >have no guarantees that an int is long enough to hold a pointer.

Is there any guarantee that a long can hold a pointer either?
-- 
allegra!phri!roy (Roy Smith)
System Administrator, Public Health Research Institute

dsi@unccvax.UUCP (Dataspan Inc) (05/16/85)

     I think it was rather appropriate, if you had read the original 
posting, you would have seen that it concerned the Alcyon Corporation
MC68000 cross-compiler, a product which does, in fact, purport to 
generate MC68000 object code that can be (and often is) run on 
MC68000 processors.

     Not everyone who reads (or gets, or is aware of) net.lang.c may
be mildly interested in the (bug) (feature), particularly if they make
their living (writing)(manufacturing)(selling) using such cross development
tools for the MC68000. 

     Pmmmmph........

David Anthony
Senior Analog Engineer
DataSpan, Inc.

P.S. This is not aimed at the 43 other people who responded in interesting
     ways to the original posting. Thanks for the replies...

.

henry@utzoo.UUCP (Henry Spencer) (05/16/85)

> >Argh, WRONG!!  Turn that "(int)" into "(long)" and I might agree.  You
> >have no guarantees that an int is long enough to hold a pointer.
> 
> I'm not sure what ANSI C says about pointers fitting into longs, but I
> don't think there is any guarantee there either.  If there IS such a
> guarantee, It doesn't seem like a good idea, since I know of 
> machines upon which pointers don't even fit in longs.  Of course, 
> pointers would have a better *chance* of fitting into a long :-).

Please notice that I said "*might* agree".  :-)
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

jchapman@watcgl.UUCP (john chapman) (05/16/85)

How about keeping this whole discussion in net.lang.c
and out of net.micro.68k (correct me if I'm wrong
but I don't see how it belongs here).