2

Possible Duplicate:
Is this self initialization valid?

Is this a well-defined C/C++ program or not?

int foo = foo;

int main()
{

}

Would foo be zero-initialized, or is it undefined behaviour?

Community
  • 1
  • 1
FrozenHeart
  • 19,844
  • 33
  • 126
  • 242
  • 1
    A better question (for C++) is: When could this possibly be useful (what is the rationale for it being legal)? – Mankarse Aug 28 '12 at 17:14
  • @Mankarse: I don't think it's deliberate that this exact code is legal, this isn't the motivating use-case. The motivation for being allowed to use non-constant expressions in static initializers is that C++ has an expectation that initializer code will run before `main` enters (for example to support statics of class type), so it makes sense. I can't remember the motivation for zero initialization prior to static initialization, I expect it has to do with the initialization order fiasco. This code happens to use both features. – Steve Jessop Aug 28 '12 at 17:17
  • @SteveJessop: I was more wondering about `foo` being in scope in its initializer. I guess it's to allow code like `struct A{ int* b; int c; } a = {&a.c, 1};`, but that seems more useful in C than in C++. – Mankarse Aug 28 '12 at 17:23
  • @SteveJessop I suspect that the 0 initialization of variables with static lifetime is because that's what C does. (And C probably did it because they could do it at no runtime cost.) But it does turn out to be a useful feature, because you can write things like `T* p = someFunction();` even where `someFunction` uses `p`, provided that `someFunction` tests whether `p` is a null pointer before hand. (I've used this for singletons: `Singleton* Singleton::ourInstance = &Singleton::instance()`, to ensure that the pointer was initialized before entering `main`... and starting threads.) – James Kanze Aug 28 '12 at 17:24
  • @Mankarse: indeed, the variable being in scope is "useful" to enable taking pointers and references to itself in the initializer. `SinglyLinkedListNode infinitelist(&infinitelist);`, `void *ptr = &ptr;` that sort of everyday thing ;-) But if you do want a self-referencing object, you might as well be allowed to create one. I think it costs more time in people wondering why it's allowed, than it does in people writing bugs that would have been prevented if it wasn't. – Steve Jessop Aug 28 '12 at 19:54
  • I used to have a problem accidentally doing this in code. If using GCC, there's a helpful warning flag, `-Winit-self` which will warn on this. – Mark Nunberg Aug 28 '12 at 21:40

4 Answers4

12

It is an ill-formed C program. In C initializers for objects with static storage duration must be constant expressions. The foo on the right-hand side is not a constant expression.

In C++ it is well-formed and has defined behavior, because of zero-initialization of objects with static storage duration (which takes place before any other initialization).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • +1 better answer. Deleted mine! – Nawaz Aug 28 '12 at 17:11
  • 1
    @NikitaTrophimov: yes, it is. It doesn't make any sense though. – Michał Górny Aug 28 '12 at 17:14
  • 2
    @Nikita Trophimov: Firstly, there's nothing wrong with self-assignment for build-in types (why would there be?). Secondly, it is not self-assignment, it is self-initialization. Self-initialization usually makes no sense, but it happens to be harmless in this specific example. – AnT stands with Russia Aug 28 '12 at 17:18
  • Thanks a lot! Is self-initialization ok for all storage types (automatic also)? – FrozenHeart Aug 28 '12 at 17:19
  • @Nikita: no, it's UB in C++ for automatic objects because they aren't zeroed prior to being initialized. In C++ you can't perform an lvalue-to-rvalue conversion on an uninitialized object. In practice I doubt the UB will manifest as anything unpleasant for `int`. C has slightly different text about uninitialized objects, such that in a typical implementation where `int` has no trap representations, I think it is defined (but useless) behavior to self-initialize an `int`. – Steve Jessop Aug 28 '12 at 17:21
  • @Steve Jessop: I know that variables with automatic storage doesn't zero-initialized, but using this variable also leads to UB, not unrecognizable results only? – FrozenHeart Aug 28 '12 at 17:25
  • Correct, there is specific text in the C++ standard saying that it is UB to do lvalue-rvalue conversion on an uninitialized object. "lvalue-to-rvalue conversion" is the standard's way of saying "read it", and if you define an automatic variable `int i = i;` then you call for an lvalue-rvalue conversion on the object `i` on the right hand side, prior to initializing it. – Steve Jessop Aug 28 '12 at 17:27
  • And what about such situation? int foo = 0; int main() { int foo = foo; } – FrozenHeart Aug 28 '12 at 17:39
  • @NikitaTrophimov: That's exactly the same. The `foo` that appears in the initialiser is the one declared inside `main` (i.e. itself). – Mike Seymour Aug 28 '12 at 17:57
1

It doesn't even compile in C. You cannot initialize global variables other than using compile time constants.

  • http://liveworkspace.org/code/076e57b1160146cb769faad23a737199 gcc 4.7.1 compile this at least – FrozenHeart Aug 28 '12 at 17:09
  • h2co3@h2co3-laptop:~$ cat const.c int foo = foo; int main() { } h2co3@h2co3-laptop:~$ gcc -o const const.c const.c:1:1: error: initializer element is not constant h2co3@h2co3-laptop:~$ –  Aug 28 '12 at 17:09
  • @NikitaTrophimov http://dl.dropbox.com/u/4960980/Screenshot%20from%202012-08-28%2019%3A09%3A55.png –  Aug 28 '12 at 17:10
  • Funny how @AndreyT who has approx 5 times more rep than me automagically gets 6 upvotes for the same answer. Well played, community. –  Aug 28 '12 at 17:11
  • lol, gcc can't compile this, while g++ can – FrozenHeart Aug 28 '12 at 17:11
  • 1
    @NikitaTrophimov because this is invalid in C only. –  Aug 28 '12 at 17:12
  • 1
    @H2CO3: if you're absolutely certain that AndreyT's answer is no better than yours then sure, blame the voters ;-p – Steve Jessop Aug 28 '12 at 17:12
  • @SteveJessop I just *blamed the voters*. –  Aug 28 '12 at 17:13
  • OK, well nevertheless I'm off to vote for Andrey's answer. He answers separately for C and C++, which is nice. – Steve Jessop Aug 28 '12 at 17:14
  • @SteveJessop it definitely is. –  Aug 28 '12 at 17:14
  • Downvoter: what's technically incorrect in my answer? –  Aug 28 '12 at 17:21
  • I didn't downvote, but I'd guess that someone didn't like a C-only answer for a question tagged both `c` and `c++` (falling under "not useful"). – ildjarn Aug 28 '12 at 19:18
  • @ildjarn well, that might be true, good point! However I'm not sure in the C++ part of the answer - and I didn't want to provide an answer with false information inside. –  Aug 28 '12 at 19:26
  • @H2CO3 just ignore this "unfair" voting. some day you will have 11 upvotes and he will have 1. – Johannes Schaub - litb Aug 28 '12 at 20:16
  • @JohannesSchaub-litb yes, that's what I'm doing :) There's not much I could do about it, anyway... –  Aug 28 '12 at 20:17
1

Static/global variables are initialized with 0. Thus:

int ThisIsZero;

int main(void)
{
    static int AndSoIsThis;
    int ButThisIsNotInitialized;
    ...
};
Christian Stieber
  • 9,954
  • 24
  • 23
0

That does not compile - and what whats the point of the question?

Ed Heal
  • 59,252
  • 17
  • 87
  • 127