5 ms·
I'm happy to say your question led me on a very interesting adventure :) Suppose x is an uninitialized int★ (pretend ★ is an asterisk---HN doesn't seem to allo
by xamuel 12y ago
I'm happy to say your question led me on a very interesting adventure :)
Suppose x is an uninitialized int★ (pretend ★ is an asterisk---HN doesn't seem to allow asterisks in comments). Suppose we do
int ★y = x; (★x)++; (★x)--;
Should y-x necessarily be 0, in the language you're looking for? Think carefully. If x had been initialized (and pointed to a valid memory location, say), would y-x necessarily be 0? Surprisingly the answer is no! It's possible that x could point to itself. In that case, (★x)++; actually changes the value of x itself, so that it is no longer cancelled out by the following (★x)--;
I guess the moral is that what you're asking for is subtler than meets the eye
- anon4 12y agoIt would be sane to ask that the literal expression "x - x" be optimised to 0, but I would never dream of asking that "y - x" be optimised to 0. Not unless the compiler can prove the values will be exactly the same in all circumstances and no, it's not allowed to just delete code that invokes undefined behaviour.
- pascal_cuoq 12y ago> no, it's not allowed to just delete code that invokes undefined behaviour. I think it is.
- cbd1984 12y ago> it's not allowed to just delete code that invokes undefined behaviour. In your mind, what does 'undefined behavior' mean? Because to the rest of us, it means "The standard says the compiler can do anything at all".
- TheLoneWolfling 12y agoI think he's also talking about my mythical C-like language that has somewhat sane rules for these things.
- cbd1984 12y ago> I think he's also talking about my mythical C-like language that has somewhat sane rules for these things. Oh, OK. It's important to realize, though, that if things get defined down too strictly, compilers will be hard-put to generate efficient code for more than one or two closely-related families of processors, which is important in a language designed to be useful for programming rather heterogeneous embedded systems (that is, more 'embedded' than ARM, perhaps with odd word sizes or similar).
- TheLoneWolfling 12y agoYep. Which is why I'm not taking about removing UB altogether, just talking about the more egregious examples of things that cause nasty bugs that aren't particularly problematic to code-gen. Not to mention that embedded systems end up using no optimization half the time anyways, because compilers go so overboard with performance that good luck trying to write safe code in them.
- deleted 12y ago[deleted]
- TheLoneWolfling 12y agoGCC 4.9.2 seems to compile this: int test(int *x) { int *y = x; (*x)++; (*x)--; return (y - x); } into this at O3: test(int*): xor eax, eax ret Effectively, into: int test(int *x) { return 0; } Which seems to contradict your adventure. I think it's because x cannot legally point to itself - x is an int ★, not a void ★. And you can't do arithmetic on a void ★, so it's not a problem there either.
- palunon 12y agoHere, GCC optimize it away. It's not required to do so. In fact, GCC can do whatever it wants in this case and still follow C standard. It may as well Yeah, you can't do x = &x. But since you didn't initialize x, it's initial value can be whatever is in memory at that particular time (or something else, nasal demons etc) If the particular value of x at runtime (there is no typechecks in C at runtime) happen to be &x, you can effectively get weird result. In fact, at -O0 : 000000000000000b <test>: b: 55 push %rbp c: 48 89 e5 mov %rsp,%rbp f: 48 89 7d e8 mov %rdi,-0x18(%rbp) 13: 48 8b 45 e8 mov -0x18(%rbp),%rax 17: 48 89 45 f8 mov %rax,-0x8(%rbp) 1b: 48 8b 45 e8 mov -0x18(%rbp),%rax 1f: 8b 00 mov (%rax),%eax 21: 8d 50 01 lea 0x1(%rax),%edx 24: 48 8b 45 e8 mov -0x18(%rbp),%rax 28: 89 10 mov %edx,(%rax) 2a: 48 8b 45 e8 mov -0x18(%rbp),%rax 2e: 8b 00 mov (%rax),%eax 30: 8d 50 ff lea -0x1(%rax),%edx 33: 48 8b 45 e8 mov -0x18(%rbp),%rax 37: 89 10 mov %edx,(%rax) 39: 48 8b 55 f8 mov -0x8(%rbp),%rdx 3d: 48 8b 45 e8 mov -0x18(%rbp),%rax 41: 48 29 c2 sub %rax,%rdx 44: 48 89 d0 mov %rdx,%rax 47: 48 c1 f8 02 sar $0x2,%rax 4b: 5d pop %rbp 4c: c3 retq
- TheLoneWolfling 12y agoI don't see what you're saying here. In C, it's undefined, so it's irrelevant. In my mythical language, the compiler is free to choose whatever initial value of x it wants. So your counterexample still doesn't work.
- MaulingMonkey 12y ago> It's possible that x could point to itself. ...in a way that doesn't violate C++'s type aliasing rules, and thus invoking undefined behavior?
- Dylan16807 12y agoThere are a lot of other ways for that to fail. You could scribble all over the executing code, or your runtime, or part of the operating system.... I don't think anyone would expect a "sane C" to let you scribble all over completely random pointers without harm. But if the pointer doesn't hit any bytes that are already in use, then "sane C" should return 0.
- EpicEng 12y agoUmmm... x certainly cannot point to itself within the rules of the language, so... poor example.