C: Passing variables between files - c

I'm trying to pass a local variable (in func1) to a function (func2) in another file, but func2 requires that as a global variable. To explain things better, here are the two files:
file1.c:
#include <something.h>
extern void func2();
void func1(){
int a=0;
func2();
}
file2.c:
#include <something.h>
extern int a; //this will fail
void func2(){
printf("%d\n",a);
}
The variable int a can't be declared as global in file1, as func1 is called recursively. Is there a better way to do this?

In file1.c:
#include <something.h>
#include "file1.h"
int a;
void func1(){
a = 0;
}
In file1.h
extern int a;
In file2.c:
#include <something.h>
#include "file1.h"
void func2(){
printf("%d\n",a);
}
So:
The variable is in file1.c
file1.h allows others to know that it exists and its type is int.
file2.c includes file1.h so that the compiler knows about var a existence before file2.c tries to use it.

Sorry I can’t comment on Ciro Pedrini’s answer, so I would say: do as he says, but also:
Make the argument list of func1 explicitly (void) (and set your compiler to complain about empty argument lists), because () just means you are not specifying what the arguments are, at least in C, which your question is tagged as.
Declare void func1(void); as well as a in file1.h.
#include file1.h in file1.c, so the compiler checks that the definitions (in file1.c) of a and func1 are consistent with their declarations (in file1.h).
But, although you may have to do this as an exercise, try to avoid passing information in global variables: arguments are usually more reliable, as it is easier to ensure that no other part of the programme alters them. And you talk about passing information to a recursive function through a global variable: in that case you must be especially careful to pick up and save the value in func1 before a recursive call alters the value - passing an argument is so much easier and more reliable!

Ciro's solution would have worked if I am only using func1 once; however func1 is called recursively so variable a cannot be global in file1 (i.e. the variable has to live on the stack and not on the heap). Here's the solution I ended up using:
File1.c:
#include <something.h>
extern void func2_new(int b);
void func1(){
int a=0;
func2_new(a);
}
File2.c:
#include <something.h>
int a;
void func2(){
printf("%d\n",a);
}
void func2_new(int b){
a=b;
func2();
}
As many have pointed out, the only answer would be to refactor func2 completely. I welcome more input to this solution.

Related

Confusion about the extern keyword and multiple source files

I am trying to fully understand how extern works, so I created 3 files, two of them are source files and the last is a header file. This is what is contained in each of them:
testingfile1.c
#include <stdio.h>
#include "testingheader.h"
int main() {
change();
int my_extern;
printf("\n%d", my_extern);
return 0;
}
testingfile2.c:
#include <stdio.h>
#include "testingheader.h"
void change() {
int my_extern;
my_extern = 15;
printf("%d", my_extern);
}
testingheader.h:
#if !defined(TESTINGHEADER_H)
#define TESTINGHEADER_H
#include <stdio.h>
extern int my_extern;
void change();
#endif
The output of this program is: 15 0. However, I thought that since my_extern is an extern int, if you were to change to the value in one source file, it's value would be changed in all of the other source files. Is this not how extern works, or am I doing something wrong in the code itself?
In both cases remove int my_extern; where you have it, because those become local variables which happen to have the same name my_extern.
extern int my_extern; just means there's an int called my_extern "out there somewhere". So you'd have to declare int my_extern somewhere at file scope, for example like this:
int my_extern = 0;
void change() {
my_extern = 15;
printf("%d", my_extern);
}
In testingfile2.c, the my_extern variable is local to the function and you are not seeing the global my_extern that the extern command is referencing. Of course, you don't have a global my_extern, so that is another problem. You would get a linker error if you actually tried to reference the global my_extern that the extern command is referencing.
The issue is you're re-declaring int my_extern; inside your functions. Therefore, C treats that as a separate variable from the global my_extern.
The statement extern int my_extern; is a declaration that a global int called my_extern will be declared somewhere. You haven't done that. Instead, you've created local my_extern variables.

Assigning a void pointer from function works in one source file, but not in two

So I'm working through this chapter of a sweet modern OpenGL tutorial, and in part of the code I assign a void pointer variable to the return value of a void * function from a second file. I got this error from gcc: initialization makes pointer from integer without a cast. As a test, I tried merging the two files and compiling again. This time, with the function in the same file as where it's called, I get no error.
I was able to reproduce this with three minimal files:
file1.c
void main() {
void *newval = foo();
}
file2.c
#include <stdlib.h>
void *foo() {
void *val;
val = malloc(10);
return val;
}
file3.c
#include <stdlib.h>
void *foo() {
void *val;
val = malloc(10);
return val;
}
void main() {
void *newval = foo();
}
file3.c is just the first two combined. My question is why when I compile one way I get an error, and the other way I get none:
$gcc file1.c file2.cfile1.c: In function ‘main’: file1.c:2:17:
warning: initialization makes pointer from integer without a cast
[enabled by default]$gcc file3.c$
I thought that the file1.c + file2.c combo was identical to file3.c. What am I missing?
In your file1.c, it seems the declaration of void *foo() is missing.
You can either include the header file containing this declaration or add line void *foo() on top of file1.c.
When compiler finds symbol foo followed by ( in main file, and there was no declaration, it assumes foo accepts any number of arguments and returns an int. So you see the warning that int is being converted to a pointer.
But in file file3.c, symbol foo is known as it is a defined function before its first usage so compiler knows that foo returns a pointer and thus no warning.
You need to declare the foo() function so that compiler knows what it is when it compiles file1.c.
Create file2.h and add in it
void *foo();
add include it in file.c
#include "file2.h"
Without declaration, the compiler assumes all unknown functions as returning int, but as your function returns void * and you are assigning it to void *, its trying to assign int to void * and hence you are getting that warning.

variable between files [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I share variables between different .c files?
If I have two source files, and one header: file1.c, file2.c, and header.h, and:
--header.h--
int i;
--file1.c--
#include <header.h>
i = 10;
int main() {
func();
return 0;
}
--file2.c--
#include <header.h>
void func() {
printf("i = %d\n", i);
return;
}
I get the warning that i defaults to an int. What could I do if I want to have i as a float for instance?
Make it
extern int i;
in the header and
int i = 10;
in file1.c.
The warning means that for the (incomplete) declaration i = 10; in file1.c, the "implicit int" rule is applied, in particular, that line is interpreted as a declaration (since an assignment cannot appear outside function scope).
You have a couple of errors in your code. The first is that you define the variable i in the header file, which means that it will be defined in all source files that include the header. Instead you should declare the variable as extern:
extern int i;
The other problem is that you can't just assign to variables in the global scope in file1.c. Instead it's there that you should define the variable:
int i = 10;
Declare it as extern in the header (this means memory for it is reserved somewhere else):
/* header.h */
extern int i;
Then define it in only one .c file, i.e. actually reserve memory for it:
/* file1.c */
int i = <initial value>;
In the header use
extern int i;
in either file1.c or file2.c have
int i = 20;
If you want float just change int to float
In 99.9% of all cases it is bad program design to share non-constant, global variables between files. There are very few cases when you actually need to do this: they are so rare that I cannot come up with any valid cases. Declarations of hardware registers perhaps.
In most of the cases, you should either use (possibly inlined) setter/getter functions ("public"), static variables at file scope ("private"), or incomplete type implementations ("private") instead.
In those few rare cases when you need to share a variable between files, do like this:
// file.h
extern int my_var;
// file.c
#include "file.h"
int my_var = something;
// main.c
#include "file.h"
use(my_var);
Never put any form of variable definition in a h-file.

C .pc file warning

I have a RefTables.pc file.
When I execute the make command, I get this warning:
RefTables.c:109: warning: type defaults to `int' in declaration of `sqlcxt'
RefTables.c:111: warning: type defaults to `int' in declaration of `sqlcx2t'
RefTables.c:113: warning: type defaults to `int' in declaration of `sqlbuft'
RefTables.c:114: warning: type defaults to `int' in declaration of `sqlgs2t'
RefTables.c:115: warning: type defaults to `int' in declaration of `sqlorat'
How can I remove it?
I am using linux & gcc compiler.
It's been a while since I used Pro*C, but I think you can add a command line option to the proc command line
code=ANSI_C
which will give prototypes for the functions named.
You can remove the warning by specifying the type of the 5 offending declarations. Actually, they must be declared with no type at all, which defaults to int in C (but generates a warning).
Edit: I found on Google this declaration.
extern sqlcxt (/*_ void **, unsigned int *, struct sqlexd *, struct sqlcxp * _*/);
The function has no return type. It should have one. Write it as follows.
extern int sqlcxt (/*_ void **, unsigned int *, struct sqlexd *, struct sqlcxp * _*/);
Or you can manually state in the compiler command line to ignore these warnings. They won't be displayed anymore.
In the future, provide a code snippet along with the warnings so that we have some context to work from. Otherwise we can only guess at what the real problem is.
I'm assuming that sqlcxt, sqlcx2t, etc., are functions. Without seeing the source code, it sounds like you don't have a declaration for those functions in scope before using them.
Here's a short example of what I mean:
int main(void)
{
foo();
return 0;
}
void foo(void)
{
// do something interesting
}
When the compiler sees the call to foo in main, it doesn't have a declaration in scope, so it assumes that foo returns int, not void, and will return a warning similar to what you got above.
If your functions are defined in the same file as they are called, there are two ways around this problem. My preferred way is to define the function before it is used:
void foo(void)
{
// do something interesting
}
int main(void)
{
foo();
return 0;
}
Another way is to have a declaration of the function in scope before calling it:
void foo(void);
int main(void)
{
foo();
return 0;
}
void foo(void)
{
// do something interesting
}
It sounds like these functions are part of a database API; if so, there should be a header file that contains declarations for those functions, and that header should be included in your source file:
/** foo.c */
#include "foo.h"
void foo(void)
{
// do something interesting
}
/** end foo.c */
/** foo.h */
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
/** end foo.h */
/** main.c */
#include "foo.h"
int main(void)
{
foo();
return 0;
}
/** end main.c */
Hope that helps.

Is There C Syntax For Function Pointer From Function Declaration

Instead of declaring a function pointer typedef for a function, is it possible to get it from the function declaration?
Typically,
int foo(int x);
typedef int (*fooFunc)(int);
fooFunc aFunc;
What I want:
int foo(int x);
foo* aFunc;
I want to use it for dlsym:
foo* aFunc;
aFunc = dlsym(lib, "foo");
aFunc(x);
If I update foo and forgot to update fooFunc, or vice versa, that would be bad. Also, I may have many functions and it would be more work to maintain both the function declarations and the function pointer typedefs that are associated with those functions.
Conclusion:
AndreyT's answer is the most portable but if you code for gcc then typeof is a great solution.
If you are talking about a declaration specifically, i.e. a non-defining declaration of a function, you can remove the redundancy by defining a typedef-name for function type and using it in both cases - to declare the function itself and to declare a pointer to it, like this
typedef int FuncType(int); /* <- function type */
FuncType foo; /* <- declaration of `int foo(int)` */
FuncType *aFunc; /* <- definition of `int (*aFunc)(int)` */
I.e. typedef-names can be used in non-defining function declarations. However, you can't use a typedef name in function definition, meaning that later you'll still have to do
int foo(int x) /* <- no way to use the above `FuncType` here */
{
/* whatever */
}
which basically renders the above trick virtually useless.
Of course, this doesn't help you to generate a pointer from an existing non-modifiable function declaration, if that's your situation.
If you have gcc, typeof works.
Update
$ cat fxf.c
#include <stdio.h>
int main(int argc, char **argv) {
typedef __typeof__ (main) function_of_same_type_as_main_t;
function_of_same_type_as_main_t *f;
printf("main() called.\n");
f = main;
if (argc) f(0, NULL);
return 0;
}
$ /usr/bin/gcc -std=c89 -pedantic -Wall -Wextra -o fxf fxf.c
fxf.c:3: warning: unused parameter ‘argv’
$ ./fxf
main() called.
main() called.
Simple answer: no, that doesn’t work. foo is a specific function which has a prototype (int (int)). Using foo in the way you did would be a bit like using an int to declare another int:
4 x; // expect this to be the same as int x
That said, there might be compiler extensions which make that work. I know that the upcoming C++ standard will have the decltype keyword to allow that. Using that, the following might work (untested, since I don’t have a supporting compiler handy):
int foo(int x);
decltype(&foo) aFunc = dlsym(lib, "foo");
It is not possible. However, you can write some code that would generate a warning, so that you would catch type mismatch. The following code generates an assignment from incompatible pointer type warning.
#include <stdio.h>
int foo(int, int);
typedef int(*fooFunc)(int);
fooFunc myfunc;
int foo(int x, int y)
{
return 2*x + y;
}
int main(int argc, char **argv)
{
myfunc = foo;
printf("myfunc : 0x%x\n", (unsigned int)myfunc);
return 0;
}
Of course, this means you would have to write this test code where the foo function is visible, so this is still more code to add for each function type. The solution here is probably a code generator, that would generate a proper header file containing both functions and their associated typedefs
Not quite the same, but you can typedef the function and use it for both the prototype and the pointer.
typedef int fooFunc(int);
fooFunc foo;
fooFunc *aFunc;

Resources