C: What variables are recognized by the compiler? - c

Suppose I had the following C code:
union foo {
int x;
double y;
} k;
char word[] = "Stack Overflow";
int number = 1;
void doStuff(int n) {
static char c = 'C';
char *ptr = malloc(n);
}
int main(int argc, char *argv[]) {
int r = 120;
k.x = 10;
doStuff(r);
return 0;
}
Which variables are recognized by the compiler? I know that the global variables k, word, and number are, as well as c because it is static, but what about the variables within the functions, such as r and *ptr?

Storage for objects is allocated at runtime according to the following (incomplete set of) rules:
If the object is declared at file scope (outside the body of any function) or with the keyword static, then storage for the object is guaranteed to be set aside and initialized when the program starts and released when the program exits.
If the object is declared within a block without the static keyword, then storage for the object is guaranteed to be set aside when the program enters the object's enclosing scope and released when the program exits that scope. In practice, most compilers that I know of will generate code to allocate all such block-scope variables at function entry.
See §6.2.4 of the online draft of the C 2011 standard for a more complete list.

Related

the difference of const initializer for global and local variable in C [duplicate]

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in g++/
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
int j;
for (j=0;j<10;j++)
{
static int i = initializer();
/*The variable i is only initialized to one*/
printf(" value of i = %d ", i);
i++;
}
return 0;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#include <stdio.h>
typedef struct foo_t {
int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
const foo_t *const f1 = &s_FooInit;
const foo_t *const f2 = s_pFooInit;
printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
return 0;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.

where the global and local variables are stored in memory in C

I work with the Aurix MUC, I tried to read the contents of the memory after the execution of a program, to see what he wrote in the memoir
I noticed that when I use a global variable in a function, the new value of this global variable after processing in the function, is not written in memory.
Here is an example:
int a = 100;
void plus (int a)
{
a = a + 17;
}
int main (void)
{
plus(a);
return 0;
}
when I display the contents of the memory I find the value 100 of a
and I do not find the new value of a which is normally 117.
I tried to declare the variable a as volatile, but it does not change anything
on the other hand if I do the calculation directly in the main like this
int a = 100;
int main (void)
{
a = a + 17
return 0;
}
like that I find the value 117 in the memory.
so I need to understand where are there save variables values used in the call functions?
and why the new variable of a is not written in memory,
and why the variables declared in local are not also written in the memory?
In this code:
int a = 100;
void plus(int a)
{
a = a + 17;
}
The int a in void plus(int a) declares a new instance of a that hides the previous a. Then, in a = a + 17;, this new instance of a is used. To have plus change the a declared outside the function, use:
int a = 100;
void plus(void)
{
a = a + 17;
}
Also, in main, change plus(a); to plus();.
In C, each identifier has a scope, where is where in the source code is visible. A declaration outside of any function has file scope, meaning the identifiers declared are visible throughout the file (technically a translation unit). In a function definition, a declaration of a parameter has block scope associated with the function—it is visible only within the function.
Because the int a = 100; has file scope, you do not need to redeclare it in plus in order to use it—it is visible inside the function, so you can just use it without a new declaration.

Why static and dynamic variable are not able allocated during initialization in c

1)invalid scenario
int *p = (int*)malloc(sizeof(p));
int main(void)
{
*p = 10;
printf("%d", *p);
}
2) invalid scenario
int main(void){
static int *p = (int*)malloc(sizeof(p));
}
3) //valid scenario
int main(void){
static int *p;
p = (int*)malloc(sizeof(p));
}
4) valid scenario
int *p;
int main(void)
{
p = (int*)malloc(sizeof(p));
*p = 10;
printf("%d", *p);
}
why Scenario 1 and 2 are invalid and Scenario 3 and 4 are valid?
Fundamentally, the only real answers boil down to simply "those are the rules". C could have been specified differently, so that the usages you are asking about were all valid, but it was not.
Perhaps you're asking about rationale. Certainly C's chosen approach is simpler, as it allows all objects of static duration (including all globals and static locals) to be initialized from data stored in the program image. Allowing initializers that are not compile-time constants would require program execution to begin in the initializers, before main() is called. That would be both more complex and messier.

Static variables local to function

I am learning storage classes in C.I have a simple code
enter code here
int f1()
{
static int i=0;
i++;
printf("%d",i);
}
int f2()
{
printf("%d",i);
}
int main()
{
f1();f2();f1();f2();
}
Compiler gives error as 'i' is undeclared in f2().
As I thought,memory static variables are allocated in data section of program memory.So any function in that file should be able to access it.
How does compiler knows that variable locally declared in function is bounded to that function only?How compiler evaluates that?
Although the lifetime of static variable isn't tied to the scope where it is defined (unlike variables with automatic storage duration):
{
static int i=0;
i++;
...
{
i++; // <-- still well defined, even in nested scope
}
}
i++; // <-- undefined
it is accessible only within this scope. The compiler just checks whether the symbol i has been defined before and it sees, that i has not been defined within that scope (the static int i=0; defines a variable that is accessible locally ~ compiler doesn't care about its lifetime).
In case you need it to be accessible out of its scope, you'll have to pass it out of it by reference (its address) or make it global:
static int i = 0;
...
{
i++;
}
...
i++; // <-- accessing global variable
static variables are indeed stored in the data section but are only in the scope of the function they are declared in.
You should do the following
static int i=0;
int f1()
{
i++;
printf("%d",i);
}
int f2()
{
printf("%d",i);
}
now the variable i can be accessed by both functions.
Always remember that the Scope is compile time not run-time. C has a flat memory structure. This means you can access anything from anywhere. You can make a pointer of i and can access it. But, C says undefined behaviour when the scope of the variable is over. This is a compiler restriction completely. You can also see the link - Is scope in C related only to compile time, as we know we can access any memory at run time? for more details. Also, this could be helpful A static variable and a global variable both reside in data segment. Still, static variable has scope limited. Why?. So, it is the translation unit that throws you the error.
Let's understand this by example.
#include "stdio.h"
int *ptr_i;
void func1()
{
static int i = 0;
ptr_i = &i;
i++;
printf("The static i=%d\r\n",i);
}
int main(int argc, char *argv[])
{
func1();
(*ptr_i)++;
func1();
}
The output of this program is the following.
The static i=1
The static i=3
As you could have understood, scope is not a run time. I was able to access the memory location used by i via pointer. Thus, you can access any memory in C as it is a flat memory structure. In this example, I accessed the memory of i using pointer to i. Note, Compiler never throw any error. Thus, scope is compile time not run time.

What is the problem with the following piece of code?

This piece of code seems to be creating some troubles while compiling. Any explanation?
int i =20;
int maxlen = i;
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
In C, you can't initialize global variables using non-constant expressions. Initializing maxlen to i fails because i is not a constant expression. It's part of the C standard.
Why not #define a constant?
#define MAXLEN 20
You can only use compile-time constants when initializing a variable at that scope. Try:
int i = 20;
int maxlen;
int main()
{
maxlen = i; // assign within the scope of a function
int j = i;
printf("i=%d , j=%d\n", i , j);
}
This Code is Invalid in C but valid in C++:
C - http://www.ideone.com/mxgMo
Error Reason -: initializer element is not constant
C++ - http://www.ideone.com/XzoeU
Works.
Because:
The C++ Standard states:
3.6.1 Main function [basic.start.main]
1 A program shall contain a global function called main, which is the designated start of the program. It is implementation defined whether a program in a freestanding environment is required to define a main function. [ Note: in a freestanding environment, start-up and termination is implementation-defined; start-up contains the execution of constructors for objects of namespace scope with static storage duration; termination contains the execution of destructors for objects with static storage duration. —end note ]
However, C99 says this:
56.7.8 Initialization
4 All the expressions in an initializer for an object that has static storage duration
shall be constant expressions or string literals.
So not just the code you posted, but something like this will also be invalid in C:
#include<stdio.h>
int needint(void);
int i =needint();
int needint(void)
{
return 1;
}
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
See here.

Resources