I have the following code snippet and I have to analyse what the output will be:
#include <stdio.h>
void f(int d);
int a = 1, b = 2, c = 3, d = 4;
int main(){
int a = 5, c = 6;
f(a);
f(b);
f(c);
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
void f(int d){
static int a = 0;
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
The output I've got is as follows:
7 12 4 4
15 26 5 11
21 27 6 5
5 27 6 4
This really baffled me. I noticed that in all 3 function calls the globally declared a suffers the assignment and that in the printf() from main() body the a declared in main() is printed. However, I am not sure about the behaviour of the rest of the variables. Is this undefined behaviour or it actually makes sense?
int a = 1, b = 2, c = 3, d = 4; ---> Global variables
int main(){
int a = 5, c = 6; ---> Shadows the global `a` and `c`
....
void f(int d){
static int a = 0; ---> local static variable visible only inside `f`
...
This is related to C's identifier scopes. The scope of a declaration is the region of the C program over which that declaration is visible. There are six scopes:
Top level identifiers: extends from the declaration point to the end of the source program file
Formal parameters in a function definiton: extends to the end of the function body
Formal parameters in function prototypes
Block (local) identifiers: extends up to the end of the block
Statement labels
Preprocessor macros
What happens in your program is known as overloading of names - a situation in which the same identifier may be associated to more than one program entity at a time. There are 5 overloading classes in C (aka namespaces):
Preprocessor macro names
Statement labels
Structure, union and enumeration tags
Component names
Other names
In C, declarations at the beginning of a block can hide declarations outside the block. For one declaration to hide another, the declared identifiers must be the same, must belong to the same overloading class, and must be declared in two distinct scopes, one of which contains the other.
With this in mind, in your code, local a and c hide global a and c in main(), and a in f() hides global a. All other references are manipulating the global variables.
void f(int d){
**static int a = 0;**
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
That's right you declared global int a and global void function f
but also you have declared static variable a
Whenever function has called, function is refering a variable of function.
if you want to avoid this problem, you should make a pointer of global variable, and refering a pointed address's value global variable.
As you know static variable is keep their last value until end of program.
each function's variable is exactly going to placed in "Stack" unless allocated by malloc.
And global variable is "Heap".
I am not sure but if you disassembly your program, static value a would go to stack
and treated with PUSH and POP instruction.
In C/C++, the identifiers in a given scope shadow the identifiers in the outer scope from the point of declaration onwards.
The following example demonstrates this:
#include <stdio.h>
const char a[] = "a";
static const char b[] = "b";
void test(const char * arg)
{
const char c[] = "c1";
printf("1-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
const char a[] = "a1";
static const char b[] = "b1";
// arg is present in this scope, we can't redeclare it
printf("1+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
const char a[] = "a2";
const char b[] = "b2";
const char arg[] = "arg2";
const char c[] = "c2";
printf("2-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
static const char a[] = "a3";
const char b[] = "b3";
static char arg[] = "arg3";
static const char c[] = "c3";
printf("3. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("2+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("1++. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
int main(void)
{
test("arg");
return 0;
}
Output:
1-. a=a b=b c=c1 arg=arg
1+. a=a1 b=b1 c=c1 arg=arg
2-. a=a2 b=b2 c=c2 arg=arg2
3. a=a3 b=b3 c=c3 arg=arg3
2+. a=a2 b=b2 c=c2 arg=arg2
1++. a=a1 b=b1 c=c1 arg=arg
This output actually makes sense.
In C/C++, the identifiers in a given scope are given preference over the identifiers in the outer scope. In this case in the function main, variables a and c will be used as local variables and rest b and d as global variables. Similarly, in the function void f(int d), d is the passed parameter, a will be used as static whenever the function is called, b and c will be used as global variables.
Hence the output will be calculated.
However you have shown the incorrect output. Correct output must be :
7 12 4 4
14 26 5 11
21 27 6 5
5 27 6 4
Related
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.
I really wonder why output is: 12 instead of 9 in following code:
#include <stdio.h>
int a = 4, b = 2;
int c = 3;
int f(void);
int main(void) {
printf("%3d\n", f());
printf("%3d%3d%3d\n", a, b, c);
return 0;
}
int f(void) {
int b, c;
a = b = c = 4;
return (a + b + c);
}
I mean since b and c local variables initialized as in the f function when function returned they no longer exist so they shouldn't be returned. Can anybody explain?
int k(void) {
int d = 5;
return d;
}
Like the k function returns nothing, right?
You made function f return summation of "values" of a, b and c, not variables themselves. By declaring variables named by b and c in function f, global variable b and c are shadowed by local variables, so any changes (like assigning 4 like you did) doesn't affect global variables with same names.
You seem to be under the impression, that f is not returning a single value but the entire expression a + b + c and that expression is evaluated in the calling function. That is not what happens.
Inside the function f, the global a is set to 4 as is the locals b and c. The values of each of those are added together resulting in the value 12, and that value is what is returned from the function.
Expressions are evaluated at the point they occur.
See the comments to see what is being referred as declaration.
If the whole variable declaration part was missing, what would be the problem?
Appears that variable definition and initialization either simultaneously or separately like in the example would suffice.
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}
If the declaration was missing then it would create no problem in main function since the locally defined variables i.e. a,b,c,f will be used in the functionality of main till its scope ends.
The declaration merely tells that the definition lies elsewhere (in some other .c file) or the definition lies after the function main in the same .c file.
There will be no problem here if the mentioned declaration is missing.
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
This tells the compiler that these variables are defined somewhere else(in another file).
/* variable definition: */
int a, b;
int c;
float f;
This is where you define variables but they are not the same as the external variables you declared since they are in the inner scope of the main function.
The scope is the place where variables live. extern keyword notes that the scope is global.
You can define variables with the same name in an inner scope and access only them as you did in the main function but it's not a good practice.
void foo()
{
int a = 5;
printf("%d\n", a); // 5
// Creating an inner scope
{
int a = 20;
printf("%d\n", a); // 20
}
printf("%d\n", a); // 5
}
The correct way to use the extern keyword with variables is like this.
//h1.h
extern int global_var; // Declaration of the variable
//c1.c
#include h1.h
int global_var = 0; // Definition of the global var. Memory is allocated here.
//main.c
#include h1.h
int main()
{
printf("global var value is %d\n", global_var); // use of the var defined and
// initialized in c1.c
return 0;
}
This program will print 0 since the variable is defined and initialized in c1.c.
Extern extends the visibility of the C variables and C functions. so that lets the compiler know that there is another place that those vars are declared and memory was allocated for them elsewhere.
for example in another c file.
if you compile a c file containing a global var for example:
int c = 5;
and you create a function on you c file that uses this c var, for example:
int someFunc(void){
return c;}
if you run someFunc in your main and print its return value, you will get 5. but you must compile both c files together.
in your program, you only use the locally allocated var declared in your main function.
When it comes to simple variables, there is really no difference between the declaration and definition. There is a difference when it comes to structs and functions. Here is an example:
// Declarations
struct myStruct;
int foo();
int main()
{
...
}
// Definitions
struct myStruct {
int a, b;
};
int foo() {
return 42;
}
In your case, you are hiding the previous declarations so that they are not accessible before the end of the scope. This is commonly called shadowing. It's basically the same thing as this:
int main()
{
int i=0;
printf("i: %d\n", i);
{
int i=42; // Now the previous i is inaccessible within this scope
printf("i: %d\n", i);
}
// And now it is accessible again
printf("i: %d\n", i);
}
I’m having a hard time with declaring my variables within C. The compiler display a message “expected constructor destructor or type conversion before token.” What am I doing wrong?
#include <stdio.h>
int count =0;
int abc;
ABC;
a = 19, b = 27, c = 3;
a = 4 + 5 * 3;
b = (4 +5) * 3;
c = 25 -(2 * (10 + (8 / 2)));
main {
printf("Enter a value please\n");
scanf("%d, , \n");
return 0;
}
Here's a rewrite, showing how to fix the various issues:
#include <stdio.h>
int count = 0; // declarations and intitializations are allowed at file
// scope (that is, outside of any function body). The
// storage for count will be set aside at program start
// and held until the program terminates.
//
// count is visible to all functions defined within this
// file, and will be visible to other files compiled and
// linked into the same program.
int main( void ) { // Implicit typing of functions is no longer allowed as of C99,
// and it was never good practice to begin with.
// IOW, the compiler will not assume a return type of
// int if a type specifier is missing. main always
// returns int, and either takes 0 or 2 arguments.
int a, b, c; // int abc; declares a *single* variable named "abc",
// not three variables named "a", "b", and "c".
// Storage for these variables will be set aside at
// function entry and held until the function exits.
//
// None of a, b, or c are visible outside of the
// function body.
// ABC has not been defined anywhere; it's not clear
// what the intent was behind ABC;
a = 19; // While not illegal, a = 19, b = 27, c = 3; is not the best style
b = 27; // in the world; it's better to make these three separate statements
c = 3; // Note that assignment statements (like any other executable
// statement) are not allowed outside of a function body.
a = 4 + 5 * 3; // fine
b = (4 +5) * 3; // fine
c = 25 -(2 * (10 + (8 / 2))); // fine
printf("Enter a value please\n"); // fine
scanf("%d", &a); // Each conversion specifier in a scanf call needs a corresponding
// argument to write the input value to, and the argument needs
// to be of the correct type. %d expects the corresponding
// argument to have type "int *" (pointer to int). The expression
// "&a" gives the address of the variable "a", and the type
// of the expression is "int *". So, this statement will read an
// integer value from standard input and store it to a.
return 0;
}
You cannot write assignments like a = 19, b = 27, c = 3; outside functions.
int count = 0; is the initialisation of a global variable, so that is allowed.
ABC; is also meaningless unless ABC has been #defined to something numerical, and even then it would be a no-op.
main is also malformed. You need to write it as int main() and make sure you return a value.
Lastly, your scanf argument list is not correct. Do consult the documentation.
It would be a good idea to study an introduction to C. Kernighan & Ritchie is an excellent book.
Suppose we have something along these lines
int f(int n);
....
do{
int a = b;
int b = f(a);
}
Is there any risk to saying
do{
int b = f(b);
}
instead, assuming a is not used elsewhere? Would it be stylistically preferable to do the former?
It is important to understand that you're not "altering" any variables here, just changing the meaning of a name.
The important concept is called the point of declaration.
Let's look at your example:
int b = 42;
{
int a = b;
int b = 23 * a;
printf("%d\n", b);
}
printf("%d\n", b);
or
int b = 42;
{
int b = 23 * b;
printf("%d\n", b);
}
printf("%d\n", b);
The name b references two objects, depending on where you are in the code, let's call them b1 and b2. This is unsurprising in case 1:
int b1 = 42;
{
int a = b1;
int b2 = 23 * a;
printf("%d\n", b2);
}
printf("%d\n", b1);
Since in C the point of declaration is before the initializer, the second example resolves differently:
int b1 = 42;
{
int b2 = 23 * b2;
printf("%d\n", b2);
}
printf("%d\n", b1);
Note that here there's no link between b1 and b2, you're initializing b2 with its own (undefined) value. A diligent compiler will warn you about this, like
x.c:7:13: warning: 'b' is used uninitialized in this function [-Wuninitialized]
As the compiler parses C code it populates a symbol table, this table contains information about all the different symbols and by symbols I mean identifiers, such as the names you give your variables, functions, and so forth ...
Most C programs are constructed out of nested scopes, global -> function -> component_statements and so on, each scope usually has its own symbol table, so the compiler uses a stack of symbol tables to keep track of everything, when a variable is looked up but isn't defined in the current symbol table it starts the search by going upward the stack until it hits global or usually last table ... but as soon one is defined in the current scope an entry is made 'shadowing' the previous.
heres a simple program to illustrate.
#include <stdio.h>
/* global accessable by most things ... */
int a = 5;
int main()
{ /* function scope */
int a = 4; /* shadowing global */
{ /* nested scope within function scope */
int b = a;
int a = b; /* shadowing function */
printf("%i\n", a);
}
return 0;
}
if you run this you would get 4 which is to be expected but anyone following your code would have to keep in the back of their mind that a is different from all the other a from global, function main ... If the programmer maintaining the code isn't aware of this things or you yourself forgot then you can have subtle run-time bugs that can be quite hard to debug ...
also note that if you run this:
#include <stdio.h>
/* global accessable by most things ... */
int a = 5;
int main()
{ /* function scope */
int a = 4; /* shadowing global */
{ /* nested scope within function scope */
int a = a; /* shadowing function, but not actually accessing outer scope */
printf("%i\n", a);
}
return 0;
}
you wouldn't get 4 but some large random int on my machine its 1606422610 since the variable is being assigned to itself that was just shadow, and c doesn't initialize variables.