| Deutsch English Français Italiano | 
| <vejbts$1772o$2@dont-email.me> View for Bookmarking (what is this?) Look up another Usenet article | 
Path: ...!weretis.net!feeder8.news.weretis.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: David Brown <david.brown@hesbynett.no> Newsgroups: comp.arch Subject: Re: 80286 protected mode Date: Mon, 14 Oct 2024 17:04:28 +0200 Organization: A noiseless patient Spider Lines: 130 Message-ID: <vejbts$1772o$2@dont-email.me> References: <2024Oct6.150415@mips.complang.tuwien.ac.at> <memo.20241006163428.19028W@jgd.cix.co.uk> <2024Oct7.093314@mips.complang.tuwien.ac.at> <7c8e5c75ce0f1e7c95ec3ae4bdbc9249@www.novabbs.org> <2024Oct8.092821@mips.complang.tuwien.ac.at> <ve5ek3$2jamt$1@dont-email.me> <2024Oct13.174537@mips.complang.tuwien.ac.at> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Mon, 14 Oct 2024 17:04:29 +0200 (CEST) Injection-Info: dont-email.me; posting-host="a978988b7d5e4bb378c8cee584e37ec1"; logging-data="1285208"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/dOGRcIx3PEYRScvFQWEDRWwtcpdPmeA0=" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0 Cancel-Lock: sha1:N0IPZ7L9nyOuWcEaNM76NyEdVII= Content-Language: en-GB In-Reply-To: <2024Oct13.174537@mips.complang.tuwien.ac.at> Bytes: 8008 On 13/10/2024 17:45, Anton Ertl wrote: > David Brown <david.brown@hesbynett.no> writes: >> When would you ever /need/ to compare pointers to different objects? >> For almost all C programmers, the answer is "never". Pretty much the >> only example people ever give of needing such comparisons is to >> implement memmove() efficiently - but you don't need to implement >> memmove(), because it is already in the standard library. > > When you implements something like, say > > vsum(double *a, double *b, double *c, size_t n); > > where a, b, and c may point to arrays in different objects, or may > point to overlapping parts of the same object, and the result vector c > in the overlap case should be the same as in the no-overlap case > (similar to memmove()), being able to compare pointers to possibly > different objects also comes in handy. > OK, I can agree with that - /if/ you need such a function. I'd suggest that when you are writing code that might call such a function, you've a very good idea whether you want to do "vec_c = vec_a + vec_b;", or "vec_c += vec_a;" (that is, "b" and "c" are the same). In other words, the programmer calling vsum already knows if there are overlaps, and you'd get the best results if you had different functions for the separate cases. It is conceivable that you don't know if there is an overlap, especially if you are only dealing with parts of arrays rather than full arrays, but I think such cases will be rare. I do think it would be convenient if there were a fully standard way to compare independent pointers (other than just for equality). Rarely needing something does not mean /never/ needing it. Since a fully defined portable method might not be possible (or at least, not efficiently possible) for some weird targets, and it's a good thing that C supports weird targets, I think perhaps the ideal would be to have some feature that exists if and only if you can do sensible comparisons. This could be an additional <stdint.h> pointer type, or some pointer compare macros, or a pre-defined macro to say if you can simply use uintptr_t for the purpose (as you can on most modern C implementations). > Another example is when the programmer uses the address as a key in, > e.g., a binary search tree. And, as you write, casting to intptr_t is > not guarenteed to work by the C standard, either. Casting to uintptr_t (why would one want a /signed/ address?) is all you need for most systems - and for any target where casting to uintptr_t will not be sufficient here, the type uintptr_t will not exist and you get a nice, safe hard compile-time error rather than silently UB code. For uses like this, you don't need to compare pointers - comparing the integers converted from the pointers is fine. (Imagine a system where converted addresses consist of a 16-bit segment number and a 16-bit offset, where the absolute address is the segment number times a scale factor, plus the offset. You can't easily compare two pointers for real address ordering by converting them to an integer type, but the result of casting to uintptr_t is still fine for your binary tree.) > > An example that probably compares pointers to the same object as far > as the C standard is concerned, but feel like different objects to the > programmer, is logic variables (in, e.g., a Prolog implementation). > When you have two free variables, and you unify them, in the > implementation one variable points to the other one. Now which should > point to which? The younger variable should point to the older one, > because it will die sooner. How do you know which variable is > younger? You compare the addresses; the variables reside on a stack, > so the younger one is closer to the top. > > If that stack is one object as far as the C standard is concerned, > there is no problem with that solution. If the stack is implemented > as several objects (to make it easier growable; I don't know if there > is a Prolog implementation that does that), you first have to check in > which piece it is (maybe with a binary search), and then possibly > compare within the stack piece at hand. > My only experience of Prolog was working through a short tutorial article when I was a teenager - I have no idea about implementations! But again I come back to the same conclusion - there are situations where being able to compare addresses can be useful, but it is very rare for most programmers to ever actually need to do so. And I think it is good that there is a widely portable way to achieve this, by casting to uintptr_t and comparing those integers. There are things that people want to do with C programming that can be done with implementation-specific code, but which cannot be done with fully portable standard code. While it is always nice if you /can/ use fully portable solutions (while still being clear and efficient), it's okay to have non-portable code when you need it. >>> An interesting case is the Forth standard. It specifies "contiguous >>> regions", which correspond to objects in C, but in Forth each address >>> is a cell and can be added, subtracted, compared, etc. irrespective of >>> where it came from. So Forth really has a flat-memory model. It has >>> had that since its origins in the 1970s. Some of the 8086 >>> implementations had some extensions for dealing with more than 64KB, >>> but they were never standardized and are now mostly forgotten. >>> >> >> Forth does not require a flat memory model in the hardware, as far as I >> am aware, any more than C does. (I appreciate that your knowledge of >> Forth is /vastly/ greater than mine.) A Forth implementation could >> interpret part of the address value as the segment or other memory block >> identifier and part of it as an index into that block, just as a C >> implementation can. > > I.e., what you are saying is that one can simulate a flat-memory model > on a segmented memory model. Yes. > Certainly. In the case of the 8086 (and > even more so on the 286) the costs of that are so high that no > widely-used Forth system went there. > OK. That's much the same as C on segmented targets. > One can also simulate segmented memory (a natural fit for many > programming languages) on flat memory. In this case the cost is much > smaller, plus it gives the maximum flexibility about segment/object > sizes and numbers. That is why flat memory has won. > Sure, flat memory is nicer in many ways.