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?
Related
I have a bunch of parameters (integers and floats); I want to write a C code where both the main program and the functions refer to the same parameters so that if I change one of them the whole code knows the new value I set. My code is formed by a main.c file which calls a function.c file; right now I declared the parameters both in the main and in the function but I think that is not robust (if I change one parameters in the main and I forget to change it also in the function I get wrong results). So here is the question: How can declare the parameters in order to change it just once and not to change it everywhere I have defined?
PS: some of the parameters depend from some others that have been previously declared
Here's what I did: I created a myparameters.h file where I declare my parameters like this: extern float x;
then I created a myparamter.c file where I define the value of the parameter: float x = 10;
However some of the parameters I define depend from others: float a = a + b; and therefore I get an error message like this one:
warning: initializer element is not a constant expression
Terminology Clarification
What you're talking about are global variables, not parameters. The word "parameters" refers to input arguments to a function:
int my_function(int arg1, char arg2) {
That is how you should be passing arguments to your functions, not through global variables.
Your Error
You're getting the error because you're trying to initialize a global variable outside of a function with a value that is not necessarily known at compile time:
int a = 2; /* legal */
int b = a + 2; /* not legal */
int main(){ /* the rest of your code */
Globals can only be initialized by constants, macros, and hardcoded values:
int a = 2; /* legal */
int b; /* also legal */
int main(){
b = a + 2; /* now that you're in a function, you can make your assignment */
In C, I am trying to pass a single-variable function into an optimization routine (optimization_routine). The optimization routine takes as input a pointer func1ptr to a function of a single float variable. However, I need to be able to pass multiple variables into this function. Thus, I am trying to construct a function pointer of one variable where all but the first inputs are "constants" into the function variable (sort of analogous to a partial derivative in calculus). I think I can do this with function pointers, but I can't figure out a syntax that makes sense.
That is, I have a function like this:
float function_all_inputs( float A, int B, float C, char D);
The optimization function requires a pointer like this:
typedef (*func1ptr)(float);
void optimization_function( func1ptr fp );
Thus, I want to construct a function of this form:
// create a function of A only at runtime using inputs B,C,D
func1ptr fp = ( & function_all_inputs(A,B,C,D))(A);
The function pointed to by fp should have the signature:
float function_one_input(float A);
Inputs B, C, and D are calculated elsewhere in the code, and thus are not known at compile-time; however, they are constant inside optimization_function.
I think I can do this in pure C using function pointers, however, I can't figure out the correct syntax. None of the examples I found online cover this case. Any advice you can provide would be appreciated.
It sounds like you are asking how to create a closure to capture parameters in C, and you can take a look at some options in the linked question.
However, without custom extensions, I think you will need to use global variables to achieve the effect you are looking for.
// Pass this wrapper with the name "wrapper" into the function
// that requires a function pointer
void wrapper(float a) {
// Where last four arguments are global variables that are computed first.
function_all_inputs(a, b, c, d, e);
}
// No need to create an explicit function pointer.
// Passing the name of the function is sufficient.
optimization_function(wrapper);
You need to write a wrapper function, like
int b;
float c;
char d;
int wrap(float a) {
return function_all_inputs(a, b, c, d);
}
Consider concurrency an re-entrancy though:
If multiple threads can use the wrapper, and need it to pass different data, make those globals thread-local:
_Thread_local int b;
If you need full re-entrancy, things get complicated:
You need to (also) save the variables before using a nested invocation with different parameters.
Writing a second (and maybe third) version of the wrapper using different globals may be better.
If you need more active at the same time, you can try a pool of those functions, though it gets unwieldy really fast. Better change your optimization-function by adding a context-parameter, and pass those extra-parameters with that.
For full freedom, you really need a way to write functions at runtime, at least enough to recover a context-pointer. That's not possible in pure C though.
If sizeof(float) >= sizeof(void*) on your platform, then you can "hack" it as follows:
typedef struct
{
float a;
int b;
float c;
char d;
}
params;
int function_all_inputs(float a, int b, float c, char d)
{
...
}
int function_one_input(float f)
{
params* p;
memcpy((void*)&p, (void*)&f, sizeof(void*));
return function_all_inputs(p->a, p->b, p->c, p->d);
}
int optimize()
{
float f;
params v;
params* p = &v;
v.a = ...;
v.b = ...;
v.c = ...;
v.d = ...;
memcpy((void*)&f, (void*)&p, sizeof(void*));
return optimization_function(function_one_input, f);
}
You weren't very consistent in your question about the return-value type, so I used int.
This may be overkill, but libffi supports creating closures in the following way:
#include <stdio.h>
#include <ffi.h>
typedef struct BCD { int B; float C; char D; } BCD;
void function_one_input_binding
(ffi_cif* cif, int* result, void** args, BCD* bcd) {
*result = function_all_inputs(*(float*)args[0], bcd->B, bcd->C, bcd->D);
}
int main() {
ffi_cif cif;
ffi_type* args[1];
ffi_closure* closure;
int (*function_one_input)(float);
// Allocate a closure.
closure = ffi_closure_alloc(sizeof(ffi_closure), &function_one_input);
// Tell libffi the parameter and return types.
args[0] = &ffi_type_float;
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_int, args);
// Bind closure data.
BCD bcd = { .B = 1, .C = 2.5, .D = 'x' };
ffi_prep_closure_loc(
closure, &cif, function_one_input_binding, &bcd, function_one_input);
// Call the function.
int result = function_one_input(42.5);
// Free the allocated closure.
ffi_closure_free(closure);
return 0;
}
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
#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);
}
How can I access a shadowed global variable in C? In C++ I can use :: for the global namespace.
If your file-scope variable is not static, then you can use a declaration that uses extern in a nested scope:
int c;
int main() {
{
int c = 0;
// now, c shadows ::c. just re-declare ::c in a
// nested scope:
{
extern int c;
c = 1;
}
// outputs 0
printf("%d\n", c);
}
// outputs 1
printf("%d\n", c);
return 0;
}
If the variable is declared with static, i don't see a way to refer to it.
There is no :: in c but you can use a getter function
#include <stdio.h>
int L=3;
inline int getL()
{
return L;
}
int main();
{
int L = 5;
printf("%d, %d", L, getL());
}
If you are talking about shadowed global var, then (on Linux) you can use dlsym() to find an address of the global variable, like this:
int myvar = 5; // global
{
int myvar = 6; // local var shadows global
int *pglob_myvar = (int *)dlsym(RTLD_NEXT, "myvar");
printf("Local: %d, global: %d\n", myvar, *pglob_myvar);
}
If you want your code to look sexy, use macro:
#define GLOBAL_ADDR(a,b) b =(typeof(b))dlsym(RTLD_NEXT, #a)
...
int *pglob_myvar;
GLOBAL_ADDR(myvar, pglob_myvar);
...
Depending on what you call shielded global variable in C, different answers are possible.
If you mean a global variable defined in another source file or a linked library, you only have to declare it again with the extern prefix:
extern int aGlobalDefinedElsewhere;
If you mean a global variable shadowed (or eclipsed, choose the terminology you prefer) by a local variable of the same name), there is no builtin way to do this in C. So you have either not to do it or to work around it. Possible solutions are:
getter/setter functions for accessing global variable (which is a good practice, in particular in multithreaded situations)
aliases to globals by way of a pointer defined before the local variable:
int noName;
{
int * aliasToNoName = &noName; /* reference to global */
int noName; /* declaration of local */
*aliasToNoName = noName; /* assign local to global */
}
what is a "shielded global variable" in pure C?
in C you have local variables, file local/global variables (static) and global variables (extern)
so file1.c:
int bla;
file2.c
extern int bla;
Yet another option is to reference the global before defining your local, or at least get a pointer to it first so you can access it after defining your local.
#include <stdio.h>
int x = 1234;
int main()
{
printf("%d\n",x); // prints global
int x = 456;
printf("%d\n",x); // prints local
}