- Now we can write good programs! - 1 Update
- How to deal with running out of stack space? - 16 Updates
- Floating point accuracy (was Re: [mildly off-topic] Valgrind and rounding errors) - 1 Update
- Switching to C# - 5 Updates
Real Troll <Real.Troll@Trolls.com>: Jun 15 04:55PM -0400 That religious nutter is gone so we can now start writing C++ programs!!!!!!!!!!!!!!!!!!!!! <======================================================================> #include <iostream> #include <vector> #include <string> using namespace std; int main() { vector<string> msg{"The", "religious", "nutter", "is", "gone", "hooray!"}; for (const string& word : msg) { cout << word << " "; } cout << endl; } <======================================================================> |
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 14 07:35PM -0400 On 6/14/19 8:44 AM, Juha Nieminen wrote: > But what exactly happens if eg. your recursion level is too big and > you run out of stack space? > To be honest, I actually don't know what the standard says about this Nothing. Almost all implementations of C++ use a stack structure to store local variables, and many of them do so using a hardware stack, but the standard says almost nothing about such issues. The closest it comes to talking about such matters is to define the term "implementation limits": "restrictions imposed upon programs by the implementation". It takes some imagination to look at those words and realize that a limited amount of stack space is one example of the kind of limit it's talking about. The standard doesn't say anything about what happens when you exceed an implementation limit, so the behavior is undefined by "ommission of any explicit definition of the behavior". It's all very vague and open to dispute. Have fun! |
Ian Collins <ian-news@hotmail.com>: Jun 15 12:14PM +1200 On 15/06/2019 00:44, Juha Nieminen wrote: > How exactly should programs be designed, if one wanted to be extra > paranoid about the possibility of running out of stack space? Or is > it something that there's simply no recourse against? Don't use recursion, do use static analysis tools to check your stack depth! -- Ian. |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 15 02:25AM +0100 >> it something that there's simply no recourse against? > Don't use recursion, do use static analysis tools to check your stack > depth! Recursion is not itself a problem. Tail call optimisation can eliminate the stack costs for some recursive programs, and even without it, some patterns of recursion are not inherently costly. For example, printing a 32-bit number as a decimal by printing a tenth of it and the printing the last digit won't recurse more than ten levels. Obviously, there are limited environments where even that is unacceptable, but they are probably the exception these days. -- Ben. |
Ian Collins <ian-news@hotmail.com>: Jun 15 01:30PM +1200 On 15/06/2019 13:25, Ben Bacarisse wrote: > the last digit won't recurse more than ten levels. Obviously, there are > limited environments where even that is unacceptable, but they are > probably the exception these days. Recursion may not be a problem, but it can defeat static analysis tools. -- Ian. |
Thiago Adams <thiago.adams@gmail.com>: Jun 14 07:20PM -0700 I don't known if any tool does that but recursive functions could be reported with a constant + number*N where N is how deep we call the function. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 15 09:59AM +0100 On Sat, 15 Jun 2019 02:25:34 +0100 > the last digit won't recurse more than ten levels. Obviously, there are > limited environments where even that is unacceptable, but they are > probably the exception these days. What you say about tail call elimination is right for C, but not so much for C++ because C++ has destructors, which means that most recursive calls which look as if they are in tail position in fact are not. To get tail call elimination to work in C++ you need to have only built-in or trivial types (in other words, only C-like types) in local scope when the recursive call is made. That is one of the reasons why Rust has not implemented tail call elimination despite it being heavily influenced by functional languages. It has adopted C++'s approach of having determinative destruction/ deallocation of objects instead of garbage collection. |
Melzzzzz <Melzzzzz@zzzzz.com>: Jun 15 10:02AM > elimination despite it being heavily influenced by functional languages. > It has adopted C++'s approach of having determinative destruction/ > deallocation of objects instead of garbage collection. It had GC in the beginning, but they ditched it for performance reasons. It also had segmented stack, which they also ditched for same reasons... -- press any key to continue or any other to quit... U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi bili naoruzani. -- Mladen Gogala |
Bonita Montero <Bonita.Montero@gmail.com>: Jun 15 01:59PM +0200 > But what exactly happens if eg. your recursion level is too big and > you run out of stack space? If you won't do massive alloca()s on most platforms there will never be such a deep recursion-level that the stack.space is exhausted. Consider that if you have thousands of recursion-levels you also will have not only an according depth of the stack but also a with of the recursions per node, i.e. your computations will last infinitely long. |
David Brown <david.brown@hesbynett.no>: Jun 15 05:13PM +0200 On 14/06/2019 23:20, Alf P. Steinbach wrote: > Then it was a misunderstanding of a machine that linked up stack frames > obtained from a single contiguous machine stack. > So a concrete link to the spec of "the mainframe" would be nice. I don't know about mainframes, but I can tell you that gcc has support for non-continguous stacks on various architectures. Spit stacks can be particularly useful in multi-threaded code (since each thread needs its own stack). <https://gcc.gnu.org/wiki/SplitStacks> (I haven't used this feature, nor can I say how common it is.) >> on most systems, but there's no guarantee. (And the stack could >> grow either up or down.) > Pointers to distinct objects can be compared using std::greater & family. True (for C++14 onwards). They can also be compared, on most architectures, by converting first to uintptr_t and comparing as integer types. But they can't be compared with standard relational operators unless the compiler documentation specifically says so. You can expect older and simpler compilers to do such comparisons in the obvious way, but newer tools are making more use of optimisations and re-arrangements based on such operations being undefined. (This is precisely why newer C++ additions, like std::greater, explicitly allow such comparisons - so that you can get them if you need them.) > On a segmented architecture one can imagine this being done by comparing > first segment selectors, and if they're equal, the segment offsets. You could imagine that, yes. But it would not match the physical ordering of addresses in an architecture such as 16-bit x86. |
David Brown <david.brown@hesbynett.no>: Jun 15 05:15PM +0200 On 14/06/2019 22:04, Thiago Adams wrote: > What do you think about adding this one? > If your hardware shares the memory between heap and stack: > 10. Don't use dynamic memory allocation Yes. On single-threaded embedded systems, it is common for the stack to grow down from the top of memory, and the heap to grow upwards from top of statically allocated data. You don't have to specify the sizes of your heap and your stack, but bad things happen if they collide. |
David Brown <david.brown@hesbynett.no>: Jun 15 05:18PM +0200 > to deal with again, unless your algorithm is broken. > The only time I've gotten stack exceptions since the 1990s is > when I've had an algorithm error. The great majority of systems are not x86, and don't have any kind of memory paging or virtual memory. It is true that it is unlikely that you will have trouble running out of stack space on a modern PC, unless you have some kind of runaway recursion, but for other kinds of system it is a very relevant question. |
David Brown <david.brown@hesbynett.no>: Jun 15 05:22PM +0200 On 15/06/2019 10:59, Chris Vine wrote: > are not. To get tail call elimination to work in C++ you need to have > only built-in or trivial types (in other words, only C-like types) in > local scope when the recursive call is made. A destructor is just a function invocation - which may be a call, or it may be inlined. If the compiler can arrange the recursive calls with tail call optimisations, it will - destructors are not any different from any other code. |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 08:25PM +0300 On 15.06.2019 14:59, Bonita Montero wrote: > Consider that if you have thousands of recursion-levels you also will > have not only an according depth of the stack but also a with of the > recursions per node, i.e. your computations will last infinitely long. I wish that were true. With our script interpreter I can get a stack overflow with just calculating factorial of 210 with a simple recursive procedure. It implements recursion on real stack, from the debugger I see that each script-level stack frame takes 4848 bytes and uses 5 C++ function call frames. The full C++ stack in the debugger is 1067 frames deep and uses up 1MB (the default stack size in MSVC++). Oh, and it takes just 0.15 seconds to get this stack overflow. There is no alloca() and there are no special coding efforts spent on optimizing the stack usage, in either direction. Fortunately this script interpreter is not meant to be used for such silly recursive procedures, so there is no urgent need to fix anything. The relevant case has sit in the backlog over 10 years. This example just shows that using such strong words like "never" and "infinitely long" is not quite appropriate, one can get stack overflow pretty easily. It's not a purely academic concern. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 15 08:34PM +0200 On 15.06.2019 17:13, David Brown wrote: > own stack). > <https://gcc.gnu.org/wiki/SplitStacks> > (I haven't used this feature, nor can I say how common it is.) It sounds challenging for debuggers. I wasn't aware of it. Thanks. >>> grow either up or down.) >> Pointers to distinct objects can be compared using std::greater & family. > True (for C++14 onwards). `std::greater` was there, providing a total ordering, in the first C++ standard, C++98. It's necessary for ordered containers of pointers. I don't know if it was part of the de-facto standard library, as specified by the ARM, in the pre-standard days. I could check but that would involve either a lot of physical work finding the book in a heap of boxes containing all kinds of stuff, or semi-illegally downloading a PDF of the ARM. >> offsets. > You could imagine that, yes. But it would not match the physical > ordering of addresses in an architecture such as 16-bit x86. I wouldn't call the original x86, with each physical memory address belonging to (if my in-head arithmetic is correct) 4096 different overlapping "segments", a segmented architecture. It was like a receiver prepared for adaption to stereo, but not actually a stereo receiver, in that it had registers and instructions that in a later version, the 286, would be employed for segment handling. There were no segment tables, just a simple arithmetic relationship (namely 16x) between selector and physical segment start address. >> single linear address space, or the possibility of doing that, that >> doesn't imply that forming the difference of two such pointers is >> necessarily possible on all platforms. Cheers!, - Alf |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 15 08:41PM +0200 On 15.06.2019 17:22, David Brown wrote: > may be inlined. If the compiler can arrange the recursive calls with > tail call optimisations, it will - destructors are not any different > from any other code. In the context of tail recursion a destructor is different, in that it's invoked implicitly, not explicitly visible in the source code. That can lead a non-expert programmer to believe tail recursion optimization will be employed, when in fact it can't be (easily) employed. Well there are other gotcha's also, e.g. that at least a decade ago Visual C++ stubbornly refused to optimize tail recursion floating point type results. So if one relies on tail recursion in C++ one should better know what one is doing, and know one's compilers. >> elimination despite it being heavily influenced by functional languages. >> It has adopted C++'s approach of having determinative destruction/ >> deallocation of objects instead of garbage collection. Interesting. Cheers!, - Alf |
Keith Thompson <kst-u@mib.org>: Jun 15 01:03PM -0700 > On 14/06/2019 23:20, Alf P. Steinbach wrote: >> On 14.06.2019 20:58, Keith Thompson wrote: [...] >>> grow either up or down.) >> Pointers to distinct objects can be compared using std::greater & family. > True (for C++14 onwards). As Alf writes in a followup, std::greater has been in the standard for a long time. There was a minor change in C++14. https://en.cppreference.com/w/cpp/utility/functional/greater > They can also be compared, on most > architectures, by converting first to uintptr_t and comparing as > integer types. Yes, but that has even fewer guarantees than std::greater. If p and q are pointers, you could have p==q but (uintptr_t)p != (uintptr_t)q if p and q hold different representations of the same value. std::greater guarantees a total ordering of pointer values, but there's no guarantee that that ordering is meaningful. If you compare addresses of three objects with automatic storage in the order in which they're created, you'll *usually* get either (&x < &y < &z) or (&x > &y > &z) (this is pseudo-code, not C++ notation), but all 6 orderings are legal. (Since the built-in relational operators < <= > >= are undefined on pointers to distinct objects, an implementation for a segmented architecture can compare just the offsets, assuming each object is in a single segment. == and != might have to do more work to distinguish between pointers to different segments with the same offset.) -- Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst> Will write code for food. void Void(void) { Void(); } /* The recursive call of the void */ |
Robert Wessel <robertwessel2@yahoo.com>: Jun 15 12:58PM -0500 On Fri, 14 Jun 2019 08:31:33 -0400, James Kuyper >on any system where FLT_RADIX is a multiple of 2 (the most common values >are 2, 10, and 16 - I've never heard of a real system where it wasn't a >multiple of 2), and on such systems 3.0/2.0 == 1.5. FSVO "real". Ternary FP has existed on at least emulated (ternary) systems. https://en.wikipedia.org/wiki/Ternac FP was implemented (in software, I believe) on the balanced ternary Soviet Sutuns, but the exact format has never been clear to me (and all of the documentation I've found is unhelpfully - at least to me - in Russian), but ternary FP seems at least a plausible choice for that. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 01:28AM +0100 On 14/06/2019 17:55, Rick C. Hodgin wrote: > Ken Thompson demonstrating his evolutionary view of the necessity of > forward declarations given modern CPU performance in compilation), > consider it to be a wonderful thing. And Satan invented fossils, yes? /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 01:29AM +0100 On 14/06/2019 17:57, Rick C. Hodgin wrote: > I had not intended to be on Usenet for C# programming. > My interests in C/C++ have not changed, nor in CAlive. I just won't > be here reading on a regular basis. Nobody cares. /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
David Brown <david.brown@hesbynett.no>: Jun 15 09:44AM +0200 On 14/06/2019 19:07, Bart wrote: > use? > I find lack of out-of-order declarations in C, to be a considerable > pain. Although I think this mainly applies to functions. As a Python user, I find being able to use things without declaring them to be a major source of errors, so I would not like that to be possible. As far as I can tell about C# (having read a small amount, but never used it), you need to declare variables before using them. Maybe functions can be used without declaring them first (as long as they are declared later). That does not seem unreasonable to me. I am not personally bothered that you need to declare functions before using them in C, but I understand that it is an inconvenience to some people. And I would rather that the language allowed calling functions before they are declared than the mess some people write with long reams of forward function declarations at the start of C files. |
Bonita Montero <Bonita.Montero@gmail.com>: Jun 15 06:49PM +0200 >> You don't have to declare everything before you use it. > Many people, including myself, consider that to be a bad thing. With todays IDEs it's not a pain when there aren't any forward -declarations. Just right-click at the symbol and click the option to guide to the definition. I like C++ but I don't think forward-declarations are an adantage. |
Bart <bc@freeuk.com>: Jun 15 05:58PM +0100 On 15/06/2019 17:49, Bonita Montero wrote: > With todays IDEs it's not a pain when there aren't any forward > -declarations. Just right-click at the symbol and click the > option to guide to the definition. What good does that do? This is not about finding the definition. It is having to ensure that when writing this (or copying it, moving it, pasting it): fn(a,b,c); that either a definition or declaration of fn has been encountered prior to this point. > I like C++ but I don't think forward-declarations are an adantage. It's a language issue. If the IDE does take care of it, it means it's generating the necessary code, and also means you aren't strictly writing in C or C++, but a version of it doesn't need you to explicitly take care of such things. If further means there there /is/ a need to deal with that nuisance. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment