Can functions declared in main access variables declared in main? - c

I have an array that I declared and initialized in main called Edges.
I have also declared some functions in main that access the array called Edges.
The code compiles and works.
Why does it work? I thought variables declared in main aren't global.
Edit: see Sourav's code.

Actually, if you declare a function inside a function, the inner function is just visible to the outer function and NOT in global scope. So, the variables declared by you and the inner function [to be appropriate, the code block] is having same scope. Hence, no issues accessing the variable.
Check this one
code
#include <stdio.h>
#include <stdlib.h>
int innerfunc();
int main()
{
int outer = 5;
int innerfunc()
{
printf("outer is %d\n", outer);
}
innerfunc();
return 0;
}
output
[sourav#infba01383 so_overflow]# ./a.out
outer is 5
[sourav#infba01383 so_overflow]#

You can't declare a function inside a function in C. This means that you can't declare function(s) inside main. Compile your code with -pedantic flag and you will see this warning for sure;
[Warning] ISO C forbids nested functions [-Wpedantic]
I compiled this code
#include <stdio.h>
void void print(int *);
int main()
{
int a[2] = {1,3};
void print(int *a)
{
printf("%d", *a);
}
print(a);
return 0;
}
and getting the warning
[Warning] ISO C forbids nested functions [-Wpedantic]

First of all, as most answers have mentioned, it is a gcc extension; not part of standard C.
Below answer is strictly confined to gcc.
gcc does treat them as any other function.
e.g. Check below code:
(I took liberty to extend your code as below:)
#include <stdio.h>
#include <stdlib.h>
typedef int operation(int num1, int num2); // for function pointer...
operation* getOperation(char oper)
{
int a=10;
int add(int x, int y){return x+y+a;}
int sub(int x, int y){return x-y+a;}
int nop(int x, int y){return a;}
if(oper=='+')return add;
if(oper=='-')return sub;
return nop;
}
int main()
{
operation *my_op;
my_op=getOperation('+');
printf("%d\n",my_op(5,3));
my_op=getOperation('-');
printf("%d\n",my_op(5,3));
return 0;
}
If you compile it with gcc -S & check the assembly code generated, it would show that
The functions - getOperation & main - are converted to assembly, without any name change. Thus these can be called from any function (in this or even from other file).
e.g.
.globl getOperation /*This line will be missing in case of static functions.*/
.type getOperation, #function
The functions - add, sub, nop - are converted to assembly with some unique random suffix.
e.g.
/*No .globl line is printed here.*/
.type add.2685, #function
Since the names are changed, you cannot call them from other functions. Only the 'parent function' (getOperation in this case) has the information of the function name. (Check for c variable scope for more details.)
However, you can use them in other functions, using function pointers, as shown in code above.
Regarding the local variables in getOperation (a for example): They are accessed from add/sub/nop using rbp register.
HINT: Compile a small code having 'local functions' with gcc -S, to understand what's exactly going on.. :-)

Nested function (annonymouse functions) are not a part of the c standard library, there is an extension which can be used.
You may declare global variables and use them throughout your programs also.
Sourav is correct actually, you may declare the function but its scope is limited to main

Related

Global variables as arguments in function C

I have a list of global variables like this:
int a, b, c, d;
These variables are used in functions designed to count them, like:
int my_func(string x)
{
//count var a//
}
Now I would like to use 'a' and e.g. 'b' as an arguments for another function which I declare this way:
int multiplication(int a, int b);
and define this way:
int multiplication(int a, int b)
{
c = a * b;
return c;
}
When I run it, I get the below error:
ac.c:75:27: error: declaration shadows a variable in the global scope [-Werror,-Wshadow]
int multiplication(int a, int b)
^
ac.c:7:41: note: previous declaration is here
int a, b, c, d;
How can I fix it? When I try to declare those variables inside functions, the whole program returns many errors.
You cannot use global variables as parameters of a function. That would make no sense either.
int multiplication (int a, int b)
What happens here in truth is that a and b are two separate function-local variables inside of the function multiplication.
They are not references for the global variables with the same names.
As function-local variables have higher priority, they shadow the global variables at the scope of the function, which means that if you use/address a or b inside of the function, they refer to the local variables, not the global ones.
That's what the diagnostic of:
"declaration shadows a variable in the global scope"
says to you. The declaration of the local variables shadows the global variable declarations inside of the function multiplication.
What you can do is pass the global variables as arguments by value to the function multiplication:
#include <stdio.h>
int multiplication (int a, int b);
int a = 5, b = 10, c = 15, d = 20;
int main (void)
{
printf("Product: %d", multiplication(a,b)); // arguments, global variables.
}
int multiplication (int a, int b) // parameters, local variables.
{
return a * b;
}
Output:
Product: 50
In this way shadowing still occurs but it isn't problematic, if you add the specific -Wno-shadow flag to turn off warnings/errors for shadowing. This is usually only a warning to hint you that shadowing occurs. Shadowing itself is not harmful.
That it is treated as error is caused by the -Werror flag, which displays warnings as erros. -Werror is great, but you should be able to differentiate real errors (issues that won't get the code compiled anyway) and only warnings which are just shown as errors to prevent code being executed with any reasonable things which potentially can give you issues with regard to the successful implementation of the algorithm or the execution.
Or just rename the parameters to a different name to make the compiler not show these warnings.
If you only want to use global variables inside of the function multiplication, you could just use c = a * b; inside of main() and omit the whole function multiplication then:
#include <stdio.h>
int a = 5, b = 10, c = 15, d = 20;
int main (void)
{
c = a * b;
printf("Product: %d", c);
}
Output:
Product: 50
To use a function which changes only global variables is considered as bad practice.
Side notes:
You should avoid global variables whenever possible, where you could pass values either by value or by reference as arguments instead.
If you got a lot of functions, where you need to pass the value of the same variable into it would make sense to use global variables.
Also as you seem to confuse the terms "argument" and "parameter", take a look at here:
What's the difference between an argument and a parameter?

why can not malloc in global but can use inline function for malloc [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 2 years ago.
Hi i have a test code for calling malloc as below:
#include <stdio.h>
#include <stdlib.h>
int *p;// = (int*)malloc(sizeof(int));
int main() {
//...
}
Of course this code will be fail when compile with the error: initializer element is not constant and i have referenced this question: Malloc function (dynamic memory allocation) resulting in an error when it is used globally. They said that we have to use malloc() in side a function. But if i change my code to:
#include <stdio.h>
#include <stdlib.h>
int *p;
static int inline test_inline(int *x) {
printf("in inline function \n");
x = (int*)malloc(sizeof(int));
return x;
}
test_inline(p);
int main(){
//...
}
As the definition of inline function: "Inline Function are those function whose definitions are small and be substituted at the place where its function call is happened. Function substitution is totally compiler choice." So this mean we can substitute the inline function test_inline in above example with the code inside it and it means we have call malloc() in global ? Question 1: is this wrong about inline or malloc() ?
Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
printf("hello");
}
test();
int main() {
//...
}
So this mean in the global we still can declaration and initialization and call function. But when we compile the above code it has a warning that warning: data definition has no type or storage class So why we have this warning with variable b ? I do not see any thing which inconsequential here. And with the line test(); i have call a function outside main(), i know this make no sense because we never run test() but i have no problem, stil build success. So back to question 1 about the malloc(), i think with the answer that "we can not call a function in global or can not initialize", i think it is not true. Is there any explain more reasonable?
Please refer to the comments.
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1; //this is only allowed, because the previous line is a tentative definition. [1]
int test() {
printf("hello");
}
test(); // this is taken as a function declaration, not a function call [2]
int main() {
//...
}
Case [1]:
Change you code to
int b = 5; // not a tentative defintion.
b = 1; // this assignment is not valid in file scope.
you'll see an error.
Case [2]:
If the signature of the function differs, you'll again see an error. Example: try the below:
float test( int x ) {
printf("hello");
return 0.5;
} //return changed to float, accepts an int as paramater.
test(); //defaults to int and no parameter - conflict!!
this will produce the error for conflicting types.
So, bottom line, no assignment, function call - all in all, no code that needs to execute at runtime, can be put into file scope. The reason behind that being, unless it's contained in a function that's called from main(), there's no way to know when / how to execute it.
You're not calling functions "globally".
Taking your example:
#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
printf("hello");
}
test();
int main() {
//...
}
In C types default to int.
So the lines
int b;
b = 1;
are basically
int b;
int b = 1;
and the lines
int test() {
printf("hello");
}
test();
are just
int test() {
printf("hello");
}
int test(); // -> this is just a matching declaration
Have a look at:
https://godbolt.org/z/3UMQAr
(try changing int test() { ... to char test() { ... and you get a compiler error telling you that those types don't match)
That said, you can't call functions there. Functions are called at runtime by your program (especially malloc, which is asking your OS to allocate memory for you). I'm not a C expert here but as far as I know C doesn't have constexpr functions, which would be the only "exception".
See: Compile-Time Function Execution
Question 1: is this wrong about inline or malloc()
kind of: malloc does have to be called in a function, but the variable it works on can be declared global. i.e. int *pointer = NULL;//global scope
then pointer = malloc(someByteCount);//called within function. Now, pointer is still global, but also has a memory address pointing to someByteCount bytes of memory.
Question 2: In C, all functions are defined on the same level of a .c file, just like main(void){...return 0}, but all functions (except main(void)) must be called within the {...} of other functions, so in short, functions cannot be called from global space.
Illustration for Q2:
//prototypes
void func1(void);
void func2(void);
void func3(void);
int main(){
int val = test_inline(p);//...
}
int main(void)
{
//legal
func1();
func2();
func3();
return 0;
}
//not legal
func1();
func2();
func3();
//definitions
void func1(void)
{
return 0;
}
void func2(void)
{
return 0;
}
void func3(void)
{
return 0;
}
Errors in syntax of your example (see comments):
int *p = NULL;//initialize before use
static int inline test_inline(int *x) {
printf("in inline function \n");
x = (int*)malloc(sizeof(int));
printf("%p\n", x);
return 0;
//return x;//function returns int, not int *
}
//... test_inline(p);//must be called in a function
int main(void){
int val = test_inline(p);//function declaration returns int, not pointer
return 0;
}
This code compiles, and runs, but as noted in comments, usefulness may be lacking.
Question 1: is this wrong about inline or malloc() ?
Neither. Your understanding of inline is incorrect. The function call may be replaced with an inline expansion of the function definition. First, let's fix the function definition because the return type int doesn't match the type of what you're actually returning:
static inline int *test_inline( int *x )
{
printf( "in inline function\n" );
x = malloc( sizeof *x );
return x; // x has type int *, so the return type of the function needs to be int *
}
If you call this function like so:
int main( void )
{
int *foo = test_inline( foo );
...
}
what the compiler may do is substitute the function call with the assembly language equivalent of the following:
int main( void )
{
int *foo;
do
{
printf( "in inline function\n" );
int *x = malloc( sizeof *x );
foo = x;
} while( 0 );
...
}
Nothing's happening "globally" here. The substitution is at the point of execution (within the body of the main function), not at the point of definition.
Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:
In the code
int test() {
printf("hello");
}
test();
the line test(); is not a function call - it's a (redundant and unnecessary) declaration. It does not execute the function.
Here are some excerpts from the language definition to clarify some of this:
6.2.4 Storage durations of objects
...
3 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.
Bold added. Any variable declared outside the body of a function (such as p in your first code snippet) has static storage duration. Since such objects are initialized before runtime, they cannot be initialized with a runtime value (such as the result of a function call).
6.7.4 Function specifiers
...
6 A function declared with an inline function specifier is an inline function. Making a
function an inline function suggests that calls to the function be as fast as possible.138)
The extent to which such suggestions are effective is implementation-defined.139)
138) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline
substitution’’. Inline substitution is not textual substitution, nor does it create a new function.
Therefore, for example, the expansion of a macro used within the body of the function uses the
definition it had at the point the function body appears, and not where the function is called; and
identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a
single address, regardless of the number of inline definitions that occur in addition to the external
definition.
139) For example, an implementation might never perform inline substitution, or might only perform inline
substitutions to calls in the scope of an inline declaration
All this means is that the inlined code behaves like it was still a single function definition, even if it's expanded in multiple places throughout the program.

Passing parameters to function in different file (gcc)

I wrote an add function for int in Add.c. Then, I passed real numbers to this add function in Main.c. The codes are shown as follows.
If I have declaration of add function before calling it, the answer is correct as 30. However, if the declaration does not exist, the answer is incorrect. Why?
Add.c
int add(int x, int y) { return x + y;}
Main.c
#include<stdio.h>
int add(int, int); // If this does not exist, the answer is not 30.
int main(void) {
printf("%d\n", add(10.5, 20.5));
}
Without the declaration, which is more specifically a prototype (a declaration with specified parameter types), you're relying on an implicit prototype-less declaration of the function (which is now an obsolescent feature of C).
The implicit prototype for function f is int f()—a function returning int and taking an unspecified number of parameters.
The way functions without prototypes are called is the arguments are promoted (lesser than int integer types to int and floats to doubles) and passed to the function in an implementation-defined way. If the arguments don't match the definition, the behavior is undefined (your case).
You could fix this (while still relying on the implicit declaration) by providing explicit casts:
#include<stdio.h>
//nothing (probably will get a compiler warning) or
int add(); /*=params unspecified*/
int main(void) {
printf("%d\n", add((int)10.5, (int)20.5));
}
thereby removing the UB (undefined behavior), or you can include the prototype as you have, which will make the compiler convert passed-in floats to match the expected types (int). In other words, with the prototype, the compiler will insert these casts for you, seeing that a conversion from float to int in (argument) assignment.
The preferred way to solve this is with a prototype included via a header which is also included in the implementation file (Add.c) so as to allow to compiler to verify the call is consistent with the definition.
To make this work, first of all, you have to include the "add.c" file into the "main.c". Coz main.c doesn't know about "add" function in add.c. (Also you should not make '.c' file to add a function or something. Instead use '.h')
Now the solution should look like this...
add.h
int add(int x, int y){
return x + y;
}
main.c
#include<stdio.h>
#include "add.h"
int main(void){
printf("%d\n", add(10, 20));
return 0;
}
Make sure to keep both the files in same directory.
Before using add in Main.c, it needs to know the declaration for this function. Without using function prototype in this case the behavior of the program would be undefined. You can either add a prototype before main as you did or you can create a separate Add.h file and put the prototype there.
In second case you need to add Add.h to both .c files.
Add.h
#ifndef ADD_H
#define ADD_H
int add(int x, int y;
#endif
Add.c
#include "Add.h"
int add(int x, int y) { return x + y;}
Main.c
#include<stdio.h>
#inclide "Add.h"
int main(void) {
printf("%d\n", add(10, 20));
}

C - how to use extern variable

I am learning how to use a extern variable, I wrote a simple program to try it but it doesnt seem to be working. I've looked at some examples but I don't know whats wrong.
Here is my code:
globals.h
#ifndef GLOBALS_H_
#define GLOBALS_H_
extern int gval;
#endif /* GLOBALS_H_ */
main.c
#include <stdio.h>
#include "globals.h"
int main() {
int gval = 4;
printf("1st value is: %i", gval);
printf("2nd value is: %i", modded());
}
modify.c
#include "globals.h"
int modded() {
return gval++;
}
The error seems to be that gval is undefined in modify.c, but I don't get how.
As it stands, you've declared a global variable gval in the header, and you've hidden that global declaration with a locally defined variable gval in the main() function. This is legal, but only sometimes (I'm tempted to say 'occasionally' or 'seldom') what is intended. If you use GCC, using the -Wshadow option would warn you about shadowing variables like that. It is generally a bad idea to shadow global variables.
The simplest fix to your code is to move the definition of gval outside main():
#include <stdio.h>
#include "globals.h"
int gval = 4;
int main(void)
{
printf("1st value is: %i", gval);
printf("2nd value is: %i", modded());
return 0;
}
However, you should note that although it will compile and run, the second value printed will be the same as the first because modded() returns the unmodified version of the value. To see the effect, you need:
#include "globals.h"
int modded(void)
{
return ++gval;
}
Were it my code, there'd be a declaration of modded() in globals.h. You should not be calling a function without a prototype in scope according to C99 and C11 (the old and current C standard). Of necessity, the original C89 standard was more lax about that rule; it had to be to accommodate the pre-existing non-standard code. However, for code written in the 21st Century, there's no real excuse for not having a prototype in scope before you use a function.
A global extern variable must be defined somewhere, but in your code, the gval in main is a local variable, there's no definition of the global variable. This line
extern int gval;
is a declaration, not a definition. In other words, you must have
int gval;
somewhere outside all functions.
Even if a global gval were defined, note that the global gval is invisible in the scope of local gval
Change your main.c to
#include <stdio.h>
#include "globals.h"
int gval; // define (allocate space for) the global variable
int main(void) {
// int gval = 4; -- wrong -- this defines and initializes a local variable that hides the global of the same name
gval = 4; // use the global variable, assigning to it ... or you could initialize it at the definition above and omit this line
printf("1st value is: %i", gval);
printf("2nd value is: %i", modded());
}
and change modded to
int modded(void) {
// return gval++; -- wrong -- this is postfix increment and returns the value *before* incrementing
return ++gval; // use prefix increment
}
You also should have a modify.h that contains the prototype for modded that you include in main.c, or just put modded inside main.c before main.
Another approach is to change modded to not return a value, since it is changing a global, thus:
void modgval(void) {
++gval; // or gval++
}
And then in main:
printf("1st value is: %i", gval);
modgval();
printf("2nd value is: %i", gval);
Just put Gval before the main declaration and you're ready to go ;)
This is a simple example describing how to share a variable between source files:
File 1:
int GlobalVariable; // explicit definition, this actually allocates as well as describing
void SomeFunction(void); // function prototype (declaration), assumes defined elsewhere, normally from include file.
int main() {
GlobalVariable = 1;
SomeFunction();
return 0;
}
File 2:
extern int GlobalVariable; // implicit declaration, this only describes and assumes allocated elsewhere, normally from include
void SomeFunction(void) { // function header (definition)
++GlobalVariable;
}
In this example, the variable GlobalVariable is defined in File 1. In order to utilize the same variable in File 2, it must be declared. Regardless of the number of files, a global variable is only defined once, however, it must be declared in any file outside of the one containing the definition.
In your case gval in main is a local variable, instead define a global variable and then use extern to share variable in different source files.

Why its returning an error?

#include <stdio.h>
int call()
{
extern int b;
b=10;
printf("%d",b);
}
int main ()
{
int b=8;
call();
return 0;
}
Why is throwing an error like these do I get the following linker error:
/tmp/ccAsFhWX.o:meka.c:(.text+0x7): undefined reference to `_b' collect2: ld returned 1 exit status
I wanted to change the b value in the other function using extern keyword but it gives me an error.am i right in doing so ?
Declaring the extern int b declares it as.... extern. It must be defined elsewhere. If it isn't, drop the extern keyword?
I think you wanted a global variable:
#include <stdio.h>
static int b;
int call()
{
b=10;
printf("%d",b);
}
int main ()
{
b=8;
call();
return 0;
}
If you declare the global b as extern you gain the possibility (and the duty) to define it elsewhere (perhaps in another translation unit (helpers.c) or a library (helpers.a) etc.)
In the C programming language, an external variable is a variable defined outside any function block. Please read about extern variables (here, for example).
Also, variables have scopes. For example, it can be a local variable, a global variable etc. You can read more about that here.
So what you have done here is declared a function scope variable in function call () without defining it using the power of extern keyword. In other words, simply tells the compiler that variable already exists somewhere. On top of that, you declared and defined another function scope variable in function main (), which has the same name. It is important to understand that those variables are totally different. So at the end of day, when you link your program, the definition of the variable b for function call () is not found. You declared it but never defined, remember?
Here are possible solutions. Do not declare multiple b variables as that was clearly not your intent. Stick with a single declaration and definition:
#include <stdio.h>
extern int b;
void call()
{
b = 10;
printf("%d\n",b);
}
int b = 8;
int main () {
call();
return 0;
}
But global variables are usually very bad - global scope makes them extremely pipeline unfriendly, introduce threading issues etc. So you must look into something like this:
#include <stdio.h>
void call (int *b)
{
printf ("%d\n", *b = 10);
}
int main () {
int b = 8;
call (&b);
return 0;
}
I'd also recommend you read the following question and answers here. It explains a lot about extern variables in C.
And by the way, you function call () is declared with int return type but returns nothing.
Hope it helps!
To change the "b" in main(), you must pass a pointer to "call" like call (&b) and then do
void call (int *b) {
*b = 10;
printf("%d",*b);
}

Resources