Xref: utzoo comp.sys.ibm.pc:22925 comp.sys.intel:649 Path: utzoo!attcan!uunet!mcvax!ukc!stl!andrew From: andrew@stl.stc.co.uk (Andrew Macpherson) Newsgroups: comp.sys.ibm.pc,comp.sys.intel Subject: Re: correct code for pointer subtraction Summary: C pointer math *a very serious bug* Message-ID: <925@acer.stl.stc.co.uk> Date: 7 Jan 89 23:07:45 GMT References: <597@mks.UUCP> <3845@pt.cs.cmu.edu> <18123@santra.UUCP> <142@bms-at.UUCP> Sender: news@stl.stc.co.uk Reply-To: "Andrew Macpherson" Organization: STC Technology Limited, London Road, Harlow, Essex, UK Lines: 59 In article <142@bms-at.UUCP> stuart@bms-at.UUCP (Stuart Gathman) writes: | In tarvaine@tukki.jyu.fi (Tapani Tarvainen) writes: | | > The same error occurs in the following program | > main() | > { | > static int a[30000]; | > printf("%d\n",&a[30000]-a); | > } | > output: -2768 | | This is entirely correct. The difference of two pointers is an *int*. This is entirely wrong. It surely has not escaped your notice that 30000 is less than MAXINT (even on an 8088 or pdp-11)? The difference of two pionters is an int, but the nescessary intermediate stages have to use arithmatic such that sizeof(the whole array)+1 can be treated as a signed quantity even if this result of the subtraction is going to be divided by the sizeof the elements of the array and then become (or be squashed into) an integer. (The +1 is needed since you are allowed to use the address of the (virtual) element one beyond the array) Hence all the comments from previous posters about using long arithmatic --- this is the simple way of acheiving the required accuracy. All those casts though are entirely spurious work-arounds for a very simple *BUG*. | If you want an unsigned difference, you need to cast to unsigned | (and/or use %u in the printf). If the difference were defined as | unsigned, how would you indicate negative differences? If you | make the difference long, all the related arithmetic gets promoted | also for a big performance hit. The solution is simple, if you | want an unsigned ptrdiff, cast or assign to unsigned. This is a fine red herring | | This is described in the Turbo C manual. and this is equally irrelevant unless you subscribe to that philosophy which holds "A documented bug is a feature" | | Don't flame the 8086 either. The same thing happens in 32-bit machines | (just much less often). 16 bits is 16 bits, and segments are not | the problem. The VAX restricts user programs to 31-bit address space | to avoid this. | -- | Stuart D. Gathman As you say the same might happen on a Vax, 68000 or whatever with really large data structures, though with the restriction on data-space size you describe this code-generator error cannot occur. The difference is that the limit is very much larger, and the structure of the processor is protecting one from this mistake rather than encouraging the unwary to make it. -- Andrew Macpherson PSI%234237100122::andrew andrew@stl.stc.co.uk - or - ...!mcvax!ukc!stl!andrew "It is always a great mistake to treat the individual on the chance that he may become a crowd" -- Mr Justice Codd: (A.P.Herbert)