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).
faustus@ucbcad.UUCP (Wayne A. Christopher) (05/17/85)
This discussion has brought up another point -- somebody posted an example where he casted a lhs, and somebody pointed out that you can't do that. What I am wondering is, why can't you? There seem to be no semantic problems involved, and it can be very useful for something like: #define FREE(ptr) free(char *) ptr); (char *) (ptr) = (char *) -1; I have wanted to do this at various times, when I don't want to have to always cast the argument to FREE and I don't ever want to reference freed data accidentally... I couldn't think of a decent way to do this that wouldn't cause compiler warnings about pointers being assigned to the int -1... Wayne
chris@umcp-cs.UUCP (Chris Torek) (05/17/85)
> #define FREE(ptr) free(char *) ptr); (char *) (ptr) = (char *) -1; > I have wanted to do this at various times... Try #define FREE(p) (free ((char *) (p)), *(char **) &(p) = (char *) -1) (not that there is any guarantee that this does anything useful and/or makes sense in the machine's architecture.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
guy@sun.uucp (Guy Harris) (05/18/85)
> This discussion has brought up another point -- somebody posted an example > where he casted a lhs, and somebody pointed out that you can't do that. > What I am wondering is, why can't you? There seem to be no semantic problems > involved, and it can be very useful for something like: > > #define FREE(ptr) free(char *) ptr); (char *) (ptr) = (char *) -1; "Why can't you?" On a machine where conversion between "int *" and "char *" wasn't just pasting a different sticker on the same bit string, what would the above construct mean if "ptr" were an "int *"? Would it mean "assign the value generated by casting -1 to a 'char *' to 'ptr' by copying bits?" If so, it might not be correct... > I have wanted to do this at various times, when I don't want to have > to always cast the argument to FREE and I don't ever want to reference > freed data accidentally... On a Sun, or a CCI Power 5/20 (or, I'll bet, on some other machines which are 68000-based or 68010/68020-based but derived from a 68000-based machine), #define FREE(ptr) free(char *) ptr); ptr = 0; will do just what you want; attempting to access virtual address 0 causes all sorts of loud bangings and clangings from your process. A simple set of changes to 4.2BSD for the VAX were posted to cause the VAX to do the same under 4.2BSD; under VMS, it does so as a matter of course, and under System V Release 2 Version 2, you can ask to have it do so. Stuffing -1 into the pointer is inappropriate (and, on a machine like the PDP-11, isn't even guaranteed to cause dereferencing of the pointer to fail); the fact that you can't get a construct like the one suggested to pass the C compiler isn't a bug, it's a feature. Guy Harris