4

in following program, is output always zero, or undefined behavior?

#include<iostream>

int main()
{
    int i= i ^ i ;
    std::cout << "i = " << i << std::endl;
}

with gcc 4.8.0 this code success compiled, and output is 0.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
Khurshid
  • 2,654
  • 2
  • 21
  • 29
  • what do you expect from the `^` operator? its bitwise XOR - as you did not initialize i variable... it gets some "random" binary stuff inside... XORs with itself and et voila ( its twice the same binary format that gets XORed => 0 ) - are you looking for http://www.cplusplus.com/reference/cmath/pow/ ? – Najzero Jul 05 '13 at 09:47
  • Why are you not initializing it ? This is a bit wise `OR`. It may return `0` – Safeer Jul 05 '13 at 09:47
  • 4
    bitwise `XOR`, to be correct. – Femaref Jul 05 '13 at 09:47
  • 1
    @Najzero Unfortunately the standard might not be so well-behaved in light of unitialized variables (even if nearly any implementation will be). He is most probably not after `pow`, but XOR and tries to use it for zero-initializing an unitialized variable (something that the compiler may very well do under the hood when zero-initializing an int, but that's the compiler). – Christian Rau Jul 05 '13 at 09:50
  • 3
    possible duplicate of [What happens to a declared, uninitialized variable in C? Does it have a value?](http://stackoverflow.com/questions/1597405/what-happens-to-a-declared-uninitialized-variable-in-c-does-it-have-a-value) – devnull Jul 05 '13 at 09:54
  • 6
    @KarolyHorvath Well, rather a proper language lawyer question (and one that isn't that irrelevant, given that this is a common assembly/compiler idiom for initialization) than a million *"why my Facebook not drawing OpenGL in jQuery?"*-questions. If you feel you need not to know anything about the inner workings of a programming language, feel free to post a *"That's XOR, what else should it do, stupid!"*-answer. – Christian Rau Jul 05 '13 at 09:56
  • 4
    This is a ridiculous question made in full knowledge it is undefined behaviour but not applying any specifics such as which operating system, which compiler, or which architecture it would be compiled for. – PP. Jul 05 '13 at 09:58
  • @Christian Rau: "this is a common assembly/compiler idiom" - yes, I know. I don't see how it is relevant here. this is a purely a language laywer question with no connection to real/actual programming whatsoever. – Karoly Horvath Jul 05 '13 at 09:59
  • Compiler/assembly - yes. But they are at least 1 level of abstraction LOWER than C++.. – quetzalcoatl Jul 05 '13 at 10:00
  • 1
    @KarolyHorvath Of course it is rubbish to do this instead of `i = 0`, but the thought process why one would want to use this (and in what larger more complex project) is certainly followable, even if not shared. – Christian Rau Jul 05 '13 at 10:01
  • 2
    @PP. I wonder where you got the impression that the OP is aware of this being undefined behaviour. – Christian Rau Jul 05 '13 at 10:03
  • I'm pedantic a person so I would go for undefined behaviour and would expect compiler warning at least. – aisbaa Jul 05 '13 at 10:07
  • @quetzalcoatl Thanks for the tag, might help to scare away *"Of course that's 0 you pedantic idiot!"*-answers and -comments. – Christian Rau Jul 05 '13 at 10:31
  • 1
    @KarolyHorvath: This question may not be as useless as you might think. It's a common machine code practice to XOR a register with itself to create a zero value, because that instruction is a) short, b) doesn't affect any of the flags, and c) contains no null bytes and is thus suitable for shellcode. Someone coming from that background may reasonably think herself able to outsmart a C++ compiler by offering this "optimized initialization". – Kerrek SB Jul 05 '13 at 11:31
  • @aisbaa: A [decent compiler *will* warn you](http://blog.llvm.org/2013/04/testing-libc-with-fsanitizeundefined.html). – Kerrek SB Jul 05 '13 at 11:53
  • @KerrekSB: Reasonbly think? You tried to depict a scenario, but I doubt that even you believe it could happen... I don't fancy any drastic solutions, but if this ever happens, please just shoot the guy :) – Karoly Horvath Jul 05 '13 at 12:19
  • 1
    @KarolyHorvath: I recently witnessed [a PHP guy](http://stackoverflow.com/q/17477749/596781) who knew about `sprintf` but had never heard of `printf` before - hey, it happens :-) With the right amount of mental balast, you can contort yourself to make any argument sound reasonable. – Kerrek SB Jul 05 '13 at 12:25
  • Possible duplicate of [Is a^a or a-a undefined behaviour if a is not initialized?](http://stackoverflow.com/questions/25074180/is-aa-or-a-a-undefined-behaviour-if-a-is-not-initialized) – phuclv Mar 16 '17 at 07:16

2 Answers2

18
int i= i ^ i ;

Since i is an automatic variable (i.e it is declared in automatic storage duration), it is not (statically) initialized yet you're reading its value to initialize it (dynamically). So your code invokes undefined behaviour.

Had you declared i at namespace level or as static, then your code would be fine:

  • Namespace level

    int i = i ^ i; //declared at namespace level (static storage duration)
    
    int main() {}
    
  • Or define locally but as static:

    int main()
    {
         static int i = i ^ i; //static storage duration
    }
    

Both of these code are fine, since i is statically initialized, as it is declared in static storage duration.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • well, after having a thought (and because he asked espec for if its undefined). IN this case its not undefined. `i` is unitialized, so you cant guess "what is inside". But as it gets `XOR`ed with itself, it ought to be zero all the time – Najzero Jul 05 '13 at 09:51
  • Why is it undefined behaviour? Since you define a variable some space of the stack is alocated which contains some bits there so the number will exist allthough it will be some trash. – Alexandru Barbarosie Jul 05 '13 at 09:52
  • The standard does not define implementation. – xen-0 Jul 05 '13 at 09:54
  • 2
    @G_G: No. Pedantically speaking, it could do **anything**. – Nawaz Jul 05 '13 at 09:57
  • 6
    XORing garbage with garbage does not have to produce zero. It can actually produce a nasty, hard-to-debug crash on some architectures, even if the compiler doesn't optimize on the assumption that you're not going to do anything as silly as deliberately invoking undefined behavior. – user2357112 Jul 05 '13 at 09:57
  • 4
    @G_G: I would like to also add, as an example, that an uninitialized `bool` is neither `true`, nor `false`. It could be anything, the spec calls its state `indeterminate`. See this question : http://stackoverflow.com/questions/4879045/fun-with-uninitialized-variables-and-compiler-gcc . I hope this helps you understand the issue here. – Nawaz Jul 05 '13 at 09:59
  • 5
    @G_G and Najzero: The problem here is, as Nawaz pointed it out, reading from an uninitialized variable is UB. As such, the standard provides **no** guarantee that two consecutive reads will yield the same value (sure, we're splitting hair here... but that's just the way the standard is written). There's not even a guarantee that it would actually read values, it could throw an exception or segfault or whatever. – syam Jul 05 '13 at 10:08
  • To be even more pedantic: There are no _uninitialized_ objects in C++. Every object is at least _default-initialized_, which of course can mean that no initialization is performed. But the object has a value, an indeterminate one. And reading an indeterminate value can result in UB. – MWid Jul 05 '13 at 10:35
  • 1
    @G_G: Please explore the meaning of "undefined behaviour" first. – Nawaz Jul 05 '13 at 10:35
  • 2
    @MWid: The spec does use the phrase "uninitialized" throughtout the text. Please don't confuse others by redefining it. The language is already HUGE and complex! – Nawaz Jul 05 '13 at 10:37
  • 2
    @G_G: The NAT thing is Itanium, and NAT XOR NAT is NAT, not zero. On Itanium that's well-defined behavior. – MSalters Jul 05 '13 at 10:38
  • 1
    C++11 4.1 [conv.lval], Lvalue-to-rvalue conversion: "If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior." – Keith Thompson Jul 05 '13 at 23:42
5

Undefined behavior. Uninitialized garbage doesn't actually have to be an unknown but valid value of the given type. On some architectures (specifically Itanium), uninitialized garbage can actually cause a crash when you try to do anything with it. See http://blogs.msdn.com/b/oldnewthing/archive/2004/01/19/60162.aspx for an explanation of how IA64's Not a Thing can mess you up.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • "given type"? we are talking about an int type! every combination of 32 or 64bit is a valid value for an int type – Gianluca Ghettini Jul 05 '13 at 10:00
  • 2
    @G_G: It doesn't have to be a combination of 32 or 64 bits! It can actually have a secret, 65th "blow up everything" bit. See link for details. – user2357112 Jul 05 '13 at 10:01
  • 2
    @G_G: It's not even guaranteed to be 32 or 64 bits. Famously Cray supercomputers implemented `int` as floating point values with the fractional part set to zero. Now imagine what happens if you take garbage, and XOR the integer part with itself. What happens with the fractional garbage?! – MSalters Jul 05 '13 at 10:06
  • Just exactly what I wanted to wrote.. Noone said that 32bit-valued integer has to be stored on 32bits. It can have tons of extra hidden flags.. They will not get XOR'red as they are not the 'userdata', but being not initialized, thay can misbehave. EDIT: Whoa. ints converted to floating point? I've to read about that. – quetzalcoatl Jul 05 '13 at 10:06
  • @user2357112 +1 for the secret "blow up everything" bit. It's no surprise that itanium never took off. :) – user4815162342 Jul 05 '13 at 10:07
  • @MSalters: the fractional garbage is set to zero – Gianluca Ghettini Jul 05 '13 at 10:28
  • 3
    @G_G: Why would an **integer** XOR set a fractional part to zero? That's not how an integer XOR works. It doesn't even touch fractional parts. – MSalters Jul 05 '13 at 10:34
  • @MSalters: None of the Cray systems I worked on (T90, T3E, SV1) did that; they represented an `int` as a 64-bit 2's-complement integer. I think some old Burroughs systems implemented integers as floating-point with an ignored exponent. (Perhaps some earlier Cray systems did as well?) – Keith Thompson Jul 05 '13 at 23:25