6 ms·
It's Undefined Behavior. So you can instrument all you want, the answer will still be wrong. You'll capture what your particular compiler does under some partic
by bestouff 5mo ago
It's Undefined Behavior. So you can instrument all you want, the answer will still be wrong. You'll capture what your particular compiler does under some particular conditions (opt flags, surrounding code, etc.) but that will not be representative of what can happen in the general case (hint : anything can happen with UB).
- amelius 5mo agoIt doesn't matter if the answer is wrong. You run the test program and then replace the code by the answer. This basically weeds out the UB.
- yongjik 5mo agoBut since it is a UB, there's no guarantee that your test program produces the same result as the same code running on production, even if you have the same compiler.
- amelius 5mo agoThat's very unlikely, and in the worst case you've reduced a difficult bug into an easier to understand bug.
- 1718627440 5mo agoThat's a valid approach, if you only use high-level language to generate assembly faster, and the assembly is your source of truth.
- thaumasiotes 5mo ago> It's Undefined Behavior. Susam's post doesn't make this clear. The quotes from K&R say that the modifications to the variable may take place in any order, but they don't directly say that doing this is Undefined Behavior, which would make it permissible to do anything, including e.g. interpreting the increments as decrements. The C99 standard is quoted saying this: >> Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. It's possible that something else in the standard defines noncompliance with this clause as Undefined Behavior. But that's not the most intuitive interpretation; what this seems to say, to me, is that the line of code `a = a++ + ++a` should fail to compile, because it's not in compliance with a requirement of the language. Compilers that produce any result at all are suffering from a bug. (It seems more likely that the actual intent is to specify that, given the line of code `b = a++ + ++a`, with a initially equal to 5, the compiler is required to ensure that the value stored at the address of a is never equal to 6 - that it begins at 5, and at some indefinite point it becomes 7, but that there is no intermediate stage between them. But I find the 'compiler failure on attempt to put multiple modifications between two sequence points' interpretation preferable.)
- Dylan16807 5mo agoCompilers are not able to prevent you from violating must/shall in the general case. So they're not held to that bar. Unless the standard says not to compile it, it's not a compiler bug. Also, imagine a situation where the line of code actually lists three different variables, but all three of them are passed in by address. It quickly becomes impossible for the compiler to know you violated the spec by reusing the same variable. And even optimizations that make sense here could corrupt the value pretty badly and possibly lead to worse errors.
- thaumasiotes 5mo ago> Also, imagine a situation where the line of code actually lists three different variables, but all three of them are passed in by address. It quickly becomes impossible for the compiler to know you violated the spec by reusing the same variable. OK. What is the value of a spec to which compliance is impossible?
- alterom 5mo ago>What is the value of a spec to which compliance is impossible? Are you saying, what's the value of a language spec that allows undefined behavior, as C does? Well, it's that it allows for compiler implementations that aren't too hard to implement and maintain. It allows for a language that's close enough to hardware (and allows you to do programming on a low level), while still offering a reasonable amount of abstraction to be useful (and usable). It's also difficult to define a formal system that won't have undefined expressions. Mathematics itself is full of them (in logic, "this sentence is a lie" has no truth value; you can't define the set of all sets, or a set of sets that don't contain themselves; etc). That said, I think we've settled on a rather silly choice here with the "++" operator. Personally, I'd do away with the ++ operator in either pre- or post- increment forms, or at least disallow it in arithmetic expressions. The only thing having it realistically accomplished is saving a few characters when writing a for-loop in C. Even for that it's not necessary. The problem with it is that, unlike normal arithmetic operators, it both returns a value and assigns one, which means that you can assign values to several variables in a single arithmetic expression, as in a = b++; ...which C, in general, allows, as in: a = (b = b + 1); The result of these two expressions, of course, is different. Now, I have the following religious belief, and it's that arithmetic operators shouldn't have side effects. That's to say, assignment and evaluation should be separate. So that when I write x = (arithmetic); ..I could be sure that the only outcome of this computation is changing the value of x. Perhaps calling the function sqrt(x) would summon Cthulhu — I'll read the documentation for it to be sure. But in general, I'd hope that calling abs(x) wouldn't change the value of x to |x| in addition to returning it. But K&R decided to have fun by saying that "x = 5;" is both an assignment and an expression with a value. Which allows one to write: x = y = z = 5; as a parlor trick. That's it, that's the only utility. Instead of defining this as a special initialization syntax and otherwise disallowing it (as Pyhthon does), they went YOLO and made assignment an expression rather than a mere statement. Which means that the very useful statement "increase the value of this variable by one" became two expressions with different values. In an ideal world, the following would be equivalent, and would not evaluate to anything you can assign to a variable: ++x; x += 1; x = x + 1; ...while "x++" would not exist at all (or would be equivalent to ++x). And that's how it is in Go. Thompson fixed the design mistake after 4-5 decades of it giving everyone headaches. Sadly, C++, Java, C# all wanted to be "like C" in basic syntax, so we're stuck with puzzles like this to this day. TL;DR: if you're asking "what's the value of the spec that makes assignment an expression", i.e. why is making "a = (b = c + d);" valid syntax a good idea, the answer is: It isn't. It's a bad decision made in 1970s that modern languages like Go no longer support.
- tengwar2 5mo agoNot nasal demons in this case (https://groups.google.com/g/comp.std.c/c/ycpVKxTZkgw/m/S2hHdTbv4d8J https://groups.google.com/g/comp.std.c/c/ycpVKxTZkgw/m/S2hHd...): thaumasiotes shows that we can expect a numeric answer.
- _kst_ 5mo agoI don't see the name "thaumasiotes" at that link, nor do I see anything relevant to the code in the title. The behavior of "int a = 5; a = a++ + ++a;" is undefined. There is no guarantee of a numeric result, because there is no guarantee of anything.
- susam 5mo agoI believe they were referring to thaumasiotes's thread here: https://news.ycombinator.com/item?id=48141294 https://news.ycombinator.com/item?id=48141294 I think the objection thaumasiotes has raised there is valid and I have made an attempt to answer it as well in the same thread.
- HarHarVeryFunny 5mo agoIt's only the order of evaluation that is undefined.
- afdbcreid 5mo agoNope, there is no sequence point in the middle and modifying an object more than once between sequence points is undefined behavior.
- _kst_ 5mo agoNo, the behavior is undefined. That means, quoting the ISO C standard, "behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this document imposes no requirements". A conforming implementation could reject it at compile time, or generate code that traps, or generate code that set a to 137, or, in principle, generate code that reformats your hard drive. Some of these behaviors are unlikely, but none are forbidden by the language standard.