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.
Related
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.
#include <stdio.h>
int foo(){
return 1;
}
int main(void) {
static int q = foo();
return 0;
}
Here is a link for the same. This is a C code and not C++. It compiles and run fine in C++ but not C.
This code was getting compilation error. Can someone please explain why is it getting error? Can static members only be initialized by constant values ? In C++ we need to DEFINE static members after declaring them , why is it not required in C ? I couldn't find any thread with similar query or a good answer.
Global and static variables can only be initialized with constant expressions known at compile time. Calling your foo() function does not constitute using a constant expression. Further, the order in which global and static variables are initialized is not specified. Generally, calling foo() would mean that there must be a certain order, because the function can reasonably expect some other variables to be already initialized.
IOW, in C, neither of your code is executed before main().
In C++ there are ways around it, but not in C.
All the static variables are compile time and the function is giving the output at run time so you are initializing a compile time variable with a run time variable which is not possible so it is giving error.
Another example may be as follows
int main()
{
int p=9;
static int x=p;
}
the above code is also gives you compile time error,The cause is same as above.
If you are doing this in C rather than C++ you can only assign static variables values that are available during compilation. So the use of foo() is not permitted due to its value not being determined until runtime.
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.
}
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What is the difference between a definition and a declaration?
I am trying to thoroughly understand "defining" and "declaring" in C.
I believe x here is defined, since external variables are automatically initialized to 0, and something that's declared and initialized is defined. Is that accurate?
int x;
main() {}
According to one x in this case is a definition, but why? It is not being initialized...
int print_hello()
{
int x;
}
Declaring is telling the compiler that there's a variable out there that looks like this.
Defining is telling the compiler that this is a variable.
One refers to the existence of a thing, the other is the thing.
In your example, the scope is what makes the difference. Declarations are made in a file scope, but in a block scope it is not possible to declare anything; therefore, the second example is a definition; because, there is nothing left to do with the int x;.
That makes the first example (in the file scope) a declaration that some int x; exists. To covert it from a declaration, you need to specify that a value is assigned to it, forcing the memory allocation. Like so: int x = 0;
C and C++ are very scope sensitive when it is analyzing constructs.
"Define" does not mean "initialized." It means something is created, rather than just referenced.
A definition allocates but does not necessarily initialize memory. This can lead to fun debugging.
Declaration introduces a name in a TU. Definition instantiates/allocates storage for that name.
int x; //definition,also a declaration. Every definition is a declaration.
int main(){}
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.