Simple Way to Check If Primitive is Uninitialized? - c

In C, from what I understand, primitives like ints and floats are initialized to 0 when they are first declared. The same is true if a struct is declared that contains primitives. I'm having trouble finding a simple way to check if primitives are uninitialized or not.
For example, let's say I have an instance variable that is of type int declared in a header file. I need to use this variable in my implementation code, and it is important for me to know if this value has been initialized or not. Checking against zero isn't really an option, because if that value really is supposed to be zero then I've reinitialized a value that has already been changed. Checking against NULL also won't work, because it isn't a pointer.
The only solution that I've come up with is initializing the variable in the first piece of executable code to some value that I know will never be relevant to the rest of the program. For example, if the value should never be below zero, then I initialize it to -1 to know that it hasn't been initialized yet. This seems really crufty though, and can cause problems if the range of values to which the variable can be assigned changes.
Any interesting suggestions to this kind of problem? Thanks in advance!

Your understanding is incorrect. Local variables are uninitialized regardless of being int or float.
Only static variables are initialized to zero. You should initialize everything before use. Even if you feel your implementation initializes the variable, you shouldn't rely on that. The standard doesn't guarantee anything. Using an uninitialized variable is an undefined behavior.

Only global primitives, pointers and data structures are initialized with zero; local variables or malloc()'d memory is not.

There is no difference between the zero that an object with static storage duration is initialised with and a zero that your code has explicitly set. A zero is just a zero.
All you can do is explicitly initialise it with a non-zero non-valid number (in the .c file that defines it):
foo.h:
extern double foo;
foo.c:
double foo = NAN;
Or, alternatively, accompany it with a flag variable that indicates if it's been initialised:
foo.h:
extern double foo;
extern int foo_initialised;
foo.c:
double foo;
int foo_initialised;

Related

Clarification about extern value in C

In C an extern variable gets the initial value of "zero".
however after reading about this particular class category.It says that declearing variable as an extern, means the value only passed the "decleration stage".How come a variable can get an initial value without procceding to the initialization stage and allocating a memory for the particular variable?
Please consider the following code:
extern int var;
int main(void)
{
var = 10;
return 0;
}
I understand why a problemetic sitution arises: we tried to initialize a value to a variable which is not allocated in the memory(the variable doesn't really exist).
My point is: why it's memory doesn't exist and followoing "extern's" terminology the variable has an initial value of "zero". In my mind it means that the memory does actually exist if it has an itial value....
For this code to be valid, another part of the program must contain the definition of var, e.g.:
int var = 0;
which is where the initial value comes from. If you don't provide an initializer then it behaves as if you initialized with = {0} (that is the rule for static storage duration variables).

static pointer, initialiser is not constant? [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 6 years ago.
What I thought static pointer is like other static variables, ones initialised with an value it have same value till end, like that the same address will be held in the static pointer. But in this case the compiler is throwing error
//initialiser element is not constant static int *a = &b[0];
#include <stdio.h>
int main(void)
{
int b[2];
static int *a = &b[0]; // removing static the program works well.
printf("%u",a);
a = &b[1];
printf("%u",a);
return 0;
}
So what is the use of static pointer?
In C, your code doesn't make sense. b has automatic storage duration so conceptually will have a different address each time main is encountered. The static will be initialised only once, and on subsequent invocations of main it may well point to something invalid.
But, and this is the interesting bit, in C++ it ought to make sense since you are not allowed to call main yourself: the behaviour on your doing so is undefined. So the inference of this is that the compiler ought to know that the static is valid for the lifetime of main, and compile the code! Perhaps there is something in the C++ Standard that explicitly forbids this.
In C you are allowed to call main recursively (even implicitly recursively), so the compiler ought to emit an error.
You have two options. Add static to int b[2], or remove it from int *a.
The address of b isn't static. It's variable, because b is a variable with automatic storage.
There may be confusion about static vs const.
Const variables will keep the same value from the time they are initialized until they go out of scope, unless const_cast<> is used, though as #Bathsheba mentioned in comment, use of const_cast<> on a variable declared const is undefined.
Static means it will get initialized at the spot first reaches but then not go out of scope until the end of program execution.

Safe to pass pointer to auto variable to function?

Suppose I have a function that declares and initializes two local variables – which by default have the storage duration auto. This function then calls a second function, to which it passes the addresses of these two local variables. Can this second function safely use these pointers?
A trivial programmatic example, to supplement that description:
#include <stdio.h>
int adder(int *a, int *b)
{
return *a + *b;
}
int main()
{
auto int a = 5; // `auto' is redundant; included for clarity
auto int b = 3;
// adder() gets the addresses of two auto variables! is this an issue?
int result = adder(&a, &b);
printf("5 + 3 = %d\n", result);
return 0;
}
This program works as expected, printing 5 + 3 = 8.
Usually, when I have questions about C, I turn to the standard, and this was no exception. Specifically, I checked ISO/IEC 9899, §6.2.4. It says there, in part:
4
An object whose identifier is declared with no linkage and without
the storage-class specifier static has automatic storage duration.
5
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way. (Entering an
enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively,
a new instance of the object is created each time. The initial value
of the object is indeterminate. If an initialization is specified for
the object, it is performed each time the declaration is reached in
the execution of the block; otherwise, the value becomes indeterminate
each time the declaration is reached.
Reading this, I reason the following points:
Variables a and b have storage duration auto, which I've made explicit using the auto keyword.
Calling the adder() function corresponds to the parenthetical in clause 5, in the partial quote above. That is, entering the adder() function "suspends, but does not end," the execution of the current block (which is main()).
Since the main() block is not "end[ed] in any way," storage for a and b is guaranteed. Thus, accessing them using the addresses &a and &b, even inside adder(), should be safe.
My question, then, is: am I correct in this? Or am I just getting "lucky," and accessing memory locations that, by happenstance, have not been overwritten?
P.S. I was unable to find an exact answer to this question through either Google or SO's search. If you can, mark this as a duplicate and I'll delete it.
Yes, it is safe and basically your assumptions are correct. The lifetime of an automatic object is from the entry in the block where it has been declared until the block terminates.
(C99, 6.2.4p5) "For such an object [...] its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
Your reasoning is correct for your particular function call chain, and you have read and quoted the relevant portions of the standard. This is a perfectly valid use of pointers to local variables.
Where you have to be wary is if the function stores the pointer values in a structure that has a lifetime longer than its own call. Consider two functions, foo(), and bar():
int *g_ptr;
void bar (int *p) {
g_ptr = p;
}
void foo () {
int x = 10;
bar(&x);
}
int main () {
foo ();
/* ...do something with g_ptr? */
return 0;
}
In this case, the variable xs lifetime ends with foo() returns. However, the pointer to x has been stored in g_ptr by bar(). In this case, it was an error for foo() to pass a pointer to its local variable x to bar().
What this means is that in order to know whether or not it is valid to pass a pointer to a local variable to a function, you have to know what that function will do with it.
Those variables are allocated in the stack. As long as you do not return from the function that declared them, they remain valid.
As I'm not yet allowed to comment, I'd rather write another answer as amendment to jxh's answer above:
Please see my elaborate answer here for a similar question. This contains a real world example where the aliasing in the called function makes your code break even though it follows all the c-language rules.
Even though it is legal in the C-language I consider it as harmful to pass pointers to automatic variables in a function call. You never know (and often you don't want to know) what exactly the called function does with the passed values. When the called function establishes an alias, you get in big trouble.

What does the C compiler do with different types of declarations?

I understand this:
int i = 3; // declaration with definition
It tells the compiler to:
Reserve space in memory to hold integer value.
Associate name with memory location.
Store the value 3 at this location.
But what does this declaration tell the compiler:
int i; // declaration
The declaration tells the compiler to reserve space for the variable i and associate the name i with that space (your points 1. and 2.).
If i is a global variable it is initialized to 0.
If it is local the value of i is undefined (probably garbage, ie. some random value) and you should assign to it before reading it.
There are two cases: at file scope (i.e. for a global declaration), and in a function.
In a function, the declaration int i; does two things: it declares a variable called i whose type is int, and it reserves some storage in memory to put a value of type int. What it does not do is give the variable a value. The storage used by i will still contain whatever garbage was there before. You need to initialize the variable, i.e. assign a value to it, before you can read a value from it. Good compilers will warn you if you don't initialize the variable.
At file scope, int i also declares a variable called i. The rest depends on other things: this is known as a tentative definition. You can have multiple such declarations in your file. At most one of these is allowed to have an initializer, making it a full-fleged definition. If none of the declarations of i at file scope have an initializer, the declaration is also a definition, and there is an implicit initialization to 0. Thus:
int i;
/* ... more code ...*/
int i;
is valid, and i will be initialized to 0 (assuming these are the only declarations of i at file scope). Whereas:
int i;
int i = 3;
is also valid, and i will be initialized to 3 when the program starts.
In practice, at file scope, there's often a difference between leaving the initialization implicit and explicitly initializing to 0. Many compilers will store an explicit 0 in the binary, but let the operating system initialize implicit zeroes automatically when the program is loaded. Don't worry about this unless you have a large global array (which shouldn't happen often) or you work on tiny embedded systems.
It says to reserve space for an integer called i. As far as what is in there is up to the compiler and is undefined.
It does the same thing as your previous declaration:
allocates space on the stack for the integer
the compiler associates a name with the space (your running program won't do this, necessarily)
the integer is not initialized.
Others have pretty much answered the question, but I will mention two points that (I think ) haven't been mentioned so far:
int i;
defines i to be an int, with garbage in it (unless i is "global"). Such garbage might be a trap representation, which means that using it could be "bad":
A trap representation is a set of bits which, when interpreted as a value of a specific type, causes undefined behavior. Trap representations are most commonly seen on floating point and pointer values, but in theory, almost any type could have trap representations. An uninitialized object might hold a trap representation. This gives the same behavior as the old rule: access to uninitialized objects produces undefined behavior.
Also, int i; could also be a tentative definition, which means that you're telling the compiler: "i is an int, and I will define it later. If I don't, then define it for me.". Here is a very good explanation of why C has tentative definitions.
There are three kinds of memory for objects:
1) external (often called "global" but that really refers to scope). Objects here are created before running the program; 2) stack (created during run time); 3) heap (eg malloced).
"int i;" either creates the object in the external memory or on the stack. If it's in a function, it's created on the stack (if "static" isn't also used.
Objects created in external memory are initialized to zero if they are not explicitly initialized (e.g, "int i = 3";
You can create an external object in a function by using the "static" keyword.
int a; // external memory with "global" scope. Initialized to 0 implicitly.
static int b; // external memory with file (module) scope. Initialized to 0 implicitly.
int c = 3; // external memory initialized to 3.
f()
{
int d; // created on the stack. Goes away when the block exits. Filled with random trash because there is no initialization.
int e = 4; // stack object initialized to 3.
static int f; // "f" is external but not global. Like all externals, it's implicitly initialized to zero.
static int g = 3; // An external like f but initialized to 3.
}

C static variables and initialization

If I have a global static variable x like in this code
#include <stdio.h>
#include <stdio.h>
static int x;
int main(void)
{
DO SOMETHING WITH x HERE
x++;
}
What will be difference if I opted to initialize x to a value first say as in
static int x = 0;
before entering "main"?
In my first case where I didn't assign a value to x, does the compiler implicitly know that x is to be set to zero as it's a static variable? I heard that we can do this with static variables.
Thanks a lot...
Static variables with explicit initialization are always initialized to zero (or null-pointer, depending on the type). The C standard §6.7.8/10 has description on this. But explicitly setting it to 0 can help others no need to wonder about the same question :).
There is a nice answer here:
Just a short excerpt:
First of all in ISO C (ANSI C), all static and global variables must be initialized before the program starts. If the programmer didn't do this explicitly, then the compiler must set them to zero. If the compiler doesn't do this, it doesn't follow ISO C. Exactly how the variables are initialized is however unspecified by the standard.
static variables are automatically initialised to zero (i.e. as though you had assigned zero to them, causing floats and pointers to become 0.0 and NULL, respectively, even if the internal representation of those values is not all bits zero).
Static variables are always implicitly initialized to zero, so there would be no difference in explicitly initializing x to zero.

Resources