int a = 5;
int b = a; //error, a is not a constant expression
int main(void)
{
static int c = a; //error, a is not a constant expression
int d = a; //okay, a don't have to be a constant expression
return 0;
}
I don't understand what happens when a C compiler handles those variable declarations.
Why was C designed to be unable to handle int b = a?
The specific rule that applies here is C 2018 6.7.9 4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
The primary reason for this arises from the way that C is typically implemented, with a compiler generating object modules (which are later linked into executables and run). In such a C implementation, initializing an object with static storage duration requires the compiler to know the initial value, whereas initializing an object with automatic storage duration does not require the compiler to know the initial value.
This is because, to initialize an object with static storage duration, the compiler must put the initial value into the object module being generated. To initialize an object with automatic storage duration, the compiler merely needs to generate instructions to get or calculate the initial value and store it in the object.
When int a = 5; and int b = a; appear outside of any function, a and b have static storage duration. At this point, the compiler could, in theory, see that a was initialized with the value five, so it has that value when used in int b = a;. However, there are some issues with this:
It requires the compiler to maintain knowledge about objects it is not currently required to maintain.
It can only be done in certain circumstances, as when the initializer for b uses only objects that have been initialized earlier in the same translation unit. Extending the language to require the compiler to support this would require more complicated rules.
It requires extending the language semantics to specify what values objects have before the program is executed at all.
Another possibility would be that, to make initializations like int b = a; work, the compiler does it by generating instructions to be executed when the program starts, possibly immediately before main is called. This adds complications, including:
If int b = a; appears in a translation unit other than the one containing main, how is the code necessary to initialize b inserted in main or in the program start-up code?
When there are multiple such initializations, some of which may depend on each other, how do you ensure they are executed in the desired order?
These problems could be solved, in theory, but C is intended to be a “simple” language.
This happens because variables declared outside any function (at file scope) or variables declared as static both get static storage duration. Such variables are initialized before main() is even called. And that early on in the execution, values that aren't pure constant expressions might not yet be available.
RAM-based hosted systems like PC might even initialize such variables in one go, at the point where the executable is copied from the hard-drive to RAM, which gives very fast initialization. Which wouldn't be possible if you did something like static x = func(); because then you definitely have to execute func() before setting x.
There's also the issue of static initialisation order. Suppose a and b were declared in separate files, which should get initialized first, a or b?
C++ unlike C has decided to allow more complex forms of initialization and as a result, C++ has very complex initialization rules. And also it is a very common C++ bug to write code depending on the order of static initialization. There are valid arguments for/against both the C and the C++ way.
Related
After stumbling onto this question and reading a little more here (c++ but this issue works the same in C/C++ AFAIN) I saw no mention to what is realy happening inside the function.
void f(){
static int c = 0;
printf("%d\n",c++);
}
int main(){
int i = 10;
while(i--)
f();
return 0;
}
In this snippet, c lifetime is the entire execution of the program, so the line static int c = 0; has no meaning in the next calls to f() since c is already a defined (static) variable, and the assignment part is also obsolete (in the next calls to f()), since it only takes place at the first time.
So, what does the compiler do? does it split f into 2 functions - f_init, f_the_real_thing where f_init initializes and f_the_real_thing prints, and calls 1 time f_init and from that onward, only calls f_the_real_thing?
The first assignment is not "obsolete" - it ensures c is zero the first time f() is called. Admittedly that is the default for statics: if no initialiser is specified, it will be initialised to zero. But a static int c = 42 will ensure c has the value 42 the first time the function is called, and the sequence of values will continue from there.
The static keyword means that the variable has static storage duration. It is only initialised once (so will have that value the first time the function is called) but changes then persist - any time the value is retrieved, the value retrieved will be the last stored in the variable.
All the compiler does is place the variable c into an area of memory that will exist - and hold whatever value it was last set to - for as long as the program is running. The specifics of how that is achieved depends on the compiler.
However, I have never seen a compiler that splits the logic of the function into multiple parts to accommodate the static.
Although the standard does not dictate how compilers must implement behavior, most compilers do a much less sophisticated thing: they place c into static memory segment, and tell the loader to place zero into c's address. This way f comes straight to pre-initialized c, and proceeds to printing and incrementing as if the declaration line where not there.
In C++ it optionally adds code to initialize c to static initialization function, which initializes all static variables. In this case, no call is required.
In essence, this amounts to c starting its lifetime before the first call to f. You can think of c's behavior as if it were a static variable outside f() with its visibility constrained to f()'s scope.
The C standard doesn't specify how the required behaviour for static storage duration must be implemented.
If you're curious about how your particular implementation handles this, then you can always check the generated assembly.
(Note that in your particular case, your code is vulnerable to concurrency issues centred around c++ not necessarily being atomic; also its vulnerability to int overflow, although i-- does act as an adequate termination condition.)
Is main really the first function or first executable statement in a C program? What if there is a global variable int a=0;?
I have always been taught that main is the starting point of a program. But what about global variable which is assigned some value and is an executable statement in my opinion?
The global variable and in general objects of static storage duration are initialized conceptually before program execution.
C11 (N1570) 5.1.2/1 Execution environments:
All objects with static storage duration shall be initialized (set to
their initial values) before program startup.
Given a hosted environment, function main is designated to be an required entry point, where program execution begins. It may be in one of two forms:
int main(void)
int main(int argc, char* argv[])
where parameters' names does not need to be the same as above (it is just a convention).
For a freestanding environment entry point is implementation-defined, that's why you can sometimes encounter void main() or any different form in C implementations for embedded devices.
C11 (N1570) 5.1.2.1/1 Freestanding environment:
In a freestanding environment (in which C program execution may take
place without any benefit of an operating system), the name and type
of the function called at program startup are implementation-defined.
main is not a starting point of the program. The starting point of the program is the entry point of the program, which is in most cases is transparent for a C programmer. Usually it is denoted by _start symbol, and defined in a startup code written in assembly or precompiled into a C runtime initialization library (like crt0.o). It is responsible for low-level initialization of stuff you are taking as given, like initializing the uninitialized static variables to zeros. After it is done, it is calling to a predefined symbol main, which is the main you know.
But what about global variable which is assigned some value and is an execuatable statement in my opinion
Your opinion is wrong.
In a global context, only a variable definition can exist, with an explicit initialization. All the executable statements (i.e, the assignment) have to reside inside a function.
To elaborate, in global context, you cannot have a statement like
int globalVar;
globalVar = 0; //error, assignement statement should be inside a function
however, the above would be perfectly valid inside a function, like
int main()
{
int localVar;
localVar = 0; //assignment is valid here.
Regarding the initialization, like
int globalVar = 0;
the initialization takes place before start of main(), so that's not really the part of execution, per se.
To elaborate the scenario of the initialization of a global variable, quoting the C11, chapter 6.2,
If the declarator or type specifier that declares the identifier
appears outside of any block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit.
and for flie scope variables,
If
the declaration of an identifier for an object has file scope and no storage-class specifier,
its linkage is external.
and for objects with external linkage,
An object whose identifier is declared without the storage-class specifier
_Thread_local, and either with external or internal linkage or with the storage-class
specifier static, has static storage duration. Its lifetime is the entire execution of the
program and its stored value is initialized only once, prior to program startup.
In a theoretical, C-standards-only program, it is.
In practice, it's usually more involved.
On Linux, AFAIK, the kernel loads your linked image into the a reserved address space and first calls the dynamic linker that the executable image specifies (unless the executable is compiled statically in which case there's no dynammic linking part).
The dynamic linker can load dependent libraries, such as the C library.
These libraries may register their own startup code, and so can you (on gcc mainly via __attribute__((constructorr))).
(User-supplied init code is especially needed for C++ where you need to run some startup code on C++ globals that have constructors.)
Then the linker calls the entry point of your image, which is _start by default (linkers allow you to choose a different name if you want to dig that deep) which is by default supplied by the C library. _start initializes the C library an continues by calling main.
In any case, simple global initializations such as int x = 42; should get compiled and linked into your executable and then get loaded by the OS (rather than your code) all at once, as part of loading the process image so there's no need for user-supplied initialization code for such variables.
If you use turbo c watch you would find that first global is declared and then execution of main starts that is at compile time data segment (giving memory to global and static variable) is initialized with 0.
So though assignment is not possible but declaration occurs at compile time.
Yes, when you declare a variable memory is allocated to it at compile time until and unless you don't use heap segment (allocating memory to pointer)i.e dynamic allocation which occurs at run time. But since global got its memory from data segment section of RAM variable is allocated memory at compile time.
Hope this helps.
While reading some questions and answers in stackoverflow I come across this question
I tried to understand it but the answers were really hard to understand especially the terms like
static storage duration
the expression cannot be evaluated during translation phase
etc...
Besides, I thought that constants are always constants (This is what I learnt from school)
Please can someone makes it a little bit easy to understand ?
In C (unlike C++), an arithmetic expression is a "constant expression" only if every value in the expression is a numeric constant or the name of an enumeration value. That is, although you might have declared a variable to be a static const int, you still cannot use that (constant) variable in a constant arithmetic expression.
Note that "constant expression" is a phrase defined by the formal standard which defines the C language. There are other expressions which are intuitively constant, but they are not included in the formal definition.
A variable with "static storage duration" is simply a variable which exists throughout the execution of the program. Most such variables are global variables (i.e. not part of any function, not even main), but in C and C++ you can have a static variable inside the scope of a function. Such a variable is initialized only once, and only a single instance of it exists regardless of how many times the function is called.
Global variables, and other variables with static storage duration, can only be initialized to a constant expression as per the above definition. This is the case whether or not they are const variables. The issue is simply that the variables have static storage duration, which means that they must be initialized before the program executes. (A variable with static storage duration exists throughout the execution of the program, so if it is initialized -- that is, given an initial value, as opposed to being assigned a value during the program's execution -- the initialization must occur before the program executes.)
In C++, a variable declared static const is considered a constant value, so it can appear in constant expressions. In C, however, that is not the case, so a C compiler does not need to track the initial value of static const variables.
There are two almost completely unrelated concepts here:
"constant expressions" are code that can be run at compile time.
4+5 is a constant expression.
const A=4; makes A into a constant expression sometimes in certain contexsts, since it's const and initialized from a constant expression 4. (This only applies to C++, not to C)
B=A; A may itself a constant expression, but B is a variable, and may not itself be in constant expressions.
const variables are variables that a function (or structure) promises not to change, though other things may change that same variable.
In C, a const-qualified variable is not the same thing as a constant. The integer literals 50 and 100 are constant expressions; their values are known at compile time (that is, they can be evaluated during the translation phase, meaning when the compiler is translating the source code into machine code). However, the variables a, c, and d won't have their values set until run time1; this means they cannot be used in a context where a compile-time constant is required2 (they cannot be evaluated during the translation phase). All the const qualifier does is tell the compiler to reject any code that attempts to modify those variables after they've been initialized.
The problem in the linked question is that endX and endY are being declared at file scope, outside of any function. Because of this, the variables have static storage duration, meaning storage for them is set aside when the program is first loaded into memory, before main executes, and held until the program terminates3. Since they are loaded before main executes, they cannot be initialized with an expression whose value won't be known until after main executes.
1. I know at least one version of gcc will build the executable file such that any static const-qualified variables will have their initial value set when the program is loaded; however, they are still treated as though they aren't initialized until after main starts.
2. C++ is different in this regard; static const-qualified variables are considered to be compile-time constants in that language.
3. Variables declared within a function or block with the static keyword also have static storage duration, meaning they exist for the lifetime of the program, but are not accessible outside of that function or block.
you are confused by const and constant.
const decorator decorates a variable and it has to have a memory location.(but not necessary true with register.) it mainly shows to human and compiler that the value of this variable is not supposed to be changed.
constant is an expression which compiler knows the meaning of.
so if you do:
const float PI = 3.14;
in file scope, it will allocate memory and having static storage duration, which essentially has the same life time as the process.
but if you do:
#define PI2 (3.14)
that's a different story, since no memory will contain this info.
so if you write:
float foo1 = 2 * PI;
float foo2 = 2 * PI2;
you can be sure that foo2 will be directly assigned to 6.28 after compilation, while whether foo1 is so or not is implementation defined, since it really depends on optimization skill called constant substitution.
I know when a program is run, the main() function is executed first. But when does the initialization of global variables declared outside the main() happens? I mean if I declare a variable like this:
unsigned long current_time = millis();
void main() {
while () {
//some code using the current_time global variable
}
}
Here, the exact time when the global variable initializes is important. Please tell what happens in this context.
Since you didn't define the language you're talking about, I assumed it to be C++.
In computer programming, a global variable is a variable that is accessible in every scope (unless shadowed). Interaction mechanisms with global variables are called global environment (see also global state) mechanisms. The global environment paradigm is contrasted with the local environment paradigm, where all variables are local with no shared memory (and therefore all interactions can be reconducted to message passing). Wikipedia.
In principle, a variable defined outside any function (that is, global, namespace, and class static variables) is initialized before main() is invoked. Such nonlocal variables in a translation unit are initialized in their declaration order (§10.4.9). If such a variable has no explicit initializer, it is by default initialized to the default for its type (§10.4.2). The default initializer value for built-in types and enumerations is 0. [...] There is no guaranteed order of initialization of global variables in different translation units. Consequently, it is unwise to create order dependencies between initializers of global variables in different compilation units. In addition, it is not possible to catch an exception thrown by the initializer of a global variable (§14.7). It is generally best to minimize the use of global variables and in particular to limit the use of global variables requiring complicated initialization. See.
(Quick answer: The C standard doesn't support this kind of initialization; you'll have to consult your compiler's documentation.)
Now that we know the language is C, we can see what the standard has to say about it.
C99 6.7.8 paragraph 4:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
And the new 2011 standard (at least the draft I has) says:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
So initializing a static object (e.g., a global such as your current_time) with a function call is a constraint violation. A compiler can reject it, or it can accept it with a warning and do whatever it likes if it provides an language extension.
The C standard doesn't say when the initialization occurs, because it doesn't permit that kind of initialization. Basically none of your code can execute before the main() function starts executing.
Apparently your compiler permits this as an extension (assuming you've actually compiled this code). You'll have to consult your compiler's documentation to find out what the semantics are.
(Normally main is declared as int main(void) or int main(int argc, char *argv[]) or equivalent, or in some implementation-defined manner. In many cases void main() indicates a programmer who's learned C from a poorly written book, of which there are far too many. But this applies only to hosted implementations. Freestanding implementations, typically for embedded systems, can define the program's entry point any way they like. Since you're targeting the Arduino, you're probably using a freestanding implementation, and you should declare main() however the compiler's documentation tells you to.)
I have seen static structure declarations quite often in a driver code I have been asked to modify.
I tried looking for information as to why structs are declared static and the motivation of doing so.
Can anyone of you please help me understand this?
The static keyword in C has several effects, depending on the context it's applied to.
when applied to a variable declared inside a function, the value of that variable will be preserved between function calls.
when applied to a variable declared outside a function, or to a function, the visibility of that variable or function is limited to the "translation unit" it's declared in - ie the file itself. For variables this boils down to a kind of "locally visible global variable".
Both usages are pretty common in relatively low-level code like drivers.
The former, and the latter when applied to variables, allow functions to retain a notion of state between calls, which can be very useful, but this can also cause all kinds of nasty problems when the code is being used in any context where it is being used concurrently, either by multiple threads or by multiple callers. If you cannot guarantee that the code will strictly be called in sequence by one "user", you can pass a kind of "context" structure that's being maintained by the caller on each call.
The latter, applied to functions, allows a programmer to make the function invisible from outside of the module, and it MAY be somewhat faster with some compilers for certain architectures because the compiler knows it doesn't have to make the variable/function available outside the module - allowing the function to be inlined for example.
Something that apparently all other answers seem to miss: static is and specifies also a storage duration for an object, along with automatic (local variables) and allocated (memory returned by malloc and friends).
Objects with static storage duration are initialized before main() starts, either with the initializer specified, or, if none was given, as if 0 had been assigned to it (for structs and arrays this goes for each member and recursively).
The second property static sets for an identifier, is its linkage, which is a concept used at link time and tells the linker which identifiers refer to the same object. The static keyword makes an identifier have internal linkage, which means it cannot refer to identifiers of the same name in another translation unit.
And to be pedantic about all the sloppy answers I've read before: a static variable can not be referenced everyhere in the file it is declared. Its scope is only from its declaration (which can be between function definitions) to the end of the source file--or even smaller, to the end of the enclosing block.
struct variable
For a struct variable like static struct S s;, this has been widely discussed at: What does "static" mean in C?
struct definition: no effect:
static struct S { int i; int j; };
is the exact same as:
struct S { int i; int j; };
so never use it. GCC 4.8 raises a warning if you do it.
This is because struct definitions have no storage, and do no generate symbols in object files like variables and functions. Just try compiling and decompiling:
struct S { int i; int j; };
int i;
with:
gcc -c main.c
nm main.o
and you will see that there is no S symbol, but there is an i symbol.
The compiler simply uses definitions to calculate the offset of fields at compile time.
This is struct definitions are usually included in headers: they won't generate multiple separate data, even if included multiple times.
The same goes for enum.
C++ struct definition: deprecated in C++11
C++11 N3337 standard draft Annex C 7.1.1:
Change: In C ++, the static or extern specifiers can only be applied to names of objects or functions
Using these specifiers with type declarations is illegal in C ++. In C, these specifiers are ignored when used
on type declarations.
See also: https://stackoverflow.com/a/31201984/895245
If you declare a variable as being static, it is visible only in that translation unit (if globally declared) or retains its value from call to call (if declared inside a function).
In your case I guess it is the first case. In that case, probably the programmer didn't want the structure to be visible from other files.
The static modifier for the struct limits the scope of visibility of the structure to the current translation unit (i.e. the file).
NOTE: This answer assumes (as other responders have indicated) that your declaration is not within a function.