Reputation: 2040
Why the following behavior is allowed by most implementations of C ? If we a use a variable itself to define it, like this:
#include <stdio.h>
int main()
{
int a = 9;
int b = ( a +b );
printf("%d",b);
}
I know that the garbage value of b
will be used but there should be some compile time warnings . It sounds a little weird to me. In languages like Python it is illegal to do such stuff :
>>> b = 9
>>> a = a + b
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
a = a + b
NameError: name 'a' is not defined
I guess Python does not put a variable to the current namespace until it is well-defined (i.e. it has a value within the current scope) while in C the above statement breaks like this:
int b = 9;
int a; // put to namespace or whatever a lookup table with garbage value
a = a + b;
It would be nice if anyone points out the philosophy behind this.
Upvotes: 3
Views: 336
Reputation: 7555
Explanation
In a C function, all of your local variable declarations happen straight away. Essentially, the compiler translates your code into:
int a;
int b;
// start of function
a = 9;
b = a + b;
// end of function
So you can see, that there is always a variable b
, it exists for the whole runtime of the function.
In Python, this doesn't happen. b
does not exist until it is assigned to for the first time.
The Python interpreter runs the code a+b
before it runs b = <the result of a+b>
. If you think about what it's doing with that intermediate result you get something equivalent to:
a = 9;
intermediate_value = a + b
b = intermediate_value
It is now clear that you are using b
before it is defined.
Philosophy
This comes down to the difference between a static language like C, and a dynamic language like Python. In a dynamic language, a lot of things that are done compile time in a static language are done at runtime instead. Such things can even include modifying the code of the running program itself. (In theory, with unfettered access to the computer's memory, you could do this in C too; but on all modern operating systems, this is impossible).
Have a read of this page http://en.wikipedia.org/wiki/Dynamic_programming_language for more information.
Upvotes: 6
Reputation: 123558
Appendix J (which is non-normative) suggests that the behavior is undefined:
The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.9, 6.8).
although I can't find explicit language in any of the referenced sections to support that (then again, my blood caffeine content is a bit low this morning, so I may be missing it).
If the behavior is undefined, then the compiler isn't required to issue a diagnostic.
Upvotes: 0
Reputation: 400029
One thing that you can do thanks to the semantics, that the variable exists right after its name ends, is a nice circular list initialization:
struct node {
struct node *next;
void *data;
}
struct node circular = { .next = &circular, .data = NULL };
This would not be possible to initialize like that, if we couldn't refer to circular
to take its address, even though we're inside the initializer expression for circular
!
Upvotes: 1
Reputation: 10604
I'm surprised that GCC doesn't spit out any warnings about the use of an uninitialized variable there (compiling with -Wall -Wpedantic
didn't give me anything). With that being said, though, C makes absolutely no assumptions about what you're doing.
Suppose, for example, you're developing for an embedded system, and, for some strange reason, you know exactly what value your stack-allocated memory holds before you initialize it -- then it's a feature. C won't stand in your way if your system to work in a way that the language developers didn't expect, and that's a good thing. It means that you know almost everything going on under the hood, so you can reason effectively about how performant your code will be.
Additionally, C doesn't have any notion of a namespace, so there's no namespace lookup to perform. Any compiler warnings about something like that stem from the compiler developer's efforts --- there's nothing in the language that distinguishes between an initialized and an uninitialzed variable.
Upvotes: 1
Reputation: 4770
In effect, you will get 4 bytes of memory (assuming an int
is 4 bytes) that keep whatever was there in the first place, then have that value added to the value of b
. You can read more about C's undefined behavior here : http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
Upvotes: 1
Reputation: 75579
The philosophy is that people who program in C know what they are doing, and you can get a lot of efficiency gain out of allowing undefined behavior, in this case with an uninitialized variable.
This article specifically mentions the example of uninitialized variables and why it allows performance gains.
This is commonly known as source of problems in C programs and there are many tools to catch these: from compiler warnings to static and dynamic analyzers. This improves performance by not requiring that all variables be zero initialized when they come into scope (as Java does). For most scalar variables, this would cause little overhead, but stack arrays and malloc'd memory would incur a memset of the storage, which could be quite costly, particularly since the storage is usually completely overwritten.
Upvotes: 1