gcc error: undefined reference to *** - c

In my main .c file, I have defined NUMBER as:
#define NUMBER '0'
In another .c file2, I have declared it as an "extern int" variable and used it. But while compiling gcc gives the following error message:
/tmp/ccsIkxdR.o: In function `file2':
file2.c:(.text+0xfd): undefined reference to `NUMBER'
collect2: error: ld returned 1 exit status
Please suggest me a way out. Thanks in advance.

When you use #define is defines a macro for the pre-processor. This macro will only be visible in the source file you defined it in. No other source file will see this macro definition, and the pre-processor will not be able to expand the macro for you in the other source file so the compiler sees the symbol NUMBER and it doesn't have a declaration for any such symbol.
To fix this you have two choices:
Put the macro in a header file that you include in both source files.
Define NUMBER as a proper variable instead of a macro, and then have an extern declaration in the other source file.

When you #define something (i.e create a pre-processor macro) in a C file, it works as text replacement, it's not the declaration of a variable. So, when you write #define NUMBER '0' and write extern int NUMBER; later, the compiler converts it to extern int '0'; before compilation, which is quite meaningless and erroneous.
If you want to define a constant and access it from elsewhere, you can write:
const int NUMBER = '0';
and
extern int NUMBER;

Since your NUMBER is of type int, you could declare it as an enumeration constant:
enum { NUMBER = '0' };
You'd have to put that in a header file (.h) and include that header in your compilation unit (.c file).

Related

Can't sort out multiple definition

I have three header files ball.h, wrappers.h, graphics.h with corresponding .c-files. Each .c file includes its corresponding header file, all of which have include guards. In addition, wrappers.c includes graphics.h and wrappers.h includes ball.h, which defines a pair of const float (and more).
In a makefile I have for each of the above pairs an entry of the form
name.o: name.c name.h with $(CC) -c $^. Finally, I have a test.c file (with a main function) which includes each of the above header files, and its makefile entry is test: test.c wrappers.o graphics.o ball.o with $(CC) $^ -o $#.
Compiling test leads to multiple definition error, saying that the aforementioned two const float are first defined in wrappers.o and ball.o.
I suppose this is because wrappers.h includes ball.h, but I have no idea how to resolve this, short of moving the offending variables or, worse, changing my code. Is the problem due to awkward includes, or because of the structure of the makefile?
ball.h excerpt:
#ifndef BALL_H
#define BALL_H
const float circleRadius = 0.025;
const float circleColor = 0;
typedef struct {
float x,y; // etc
} ball_t;
// various function prototypes
#endif /* BALL_H */
Converting comments into an answer.
In C, each time you include ball.h, you get global copies of the circleRadius and circleColor constants defined. Either they need to be static (as well as const float), or you need to declare them extern in the header (without an initializer) and define them fully in one source file.
This is an area where the rules in C++ are different from those in C; beware which compiler you use.
I haven't used extern before; how should I use it here? (And now that you mention it, static would probably be a good idea for this particular project, but I'd like to try the extern solution as well.)
In the header, write:
extern const float circleRadius;
In one source file, write:
const float circleRadius = 0.025;
Repeat for colour too. For integer values, you could consider using enum instead (See static const vs #define vs enum for more details.) For floating point (or, indeed, integer values), you could use this in the header instead:
#define CIRCLE_RADIUS 0.025
Obviously, you'd change the spelling of the references (all caps is customary for #define — and many enum — constants).
Also, as pointed out by WhozCraig in a comment, the question Why do we need the extern keyword in C if file scope declarations have external linkage by default? may be helpful.

Why is use of an array defined in File1 working in File2 (only declared there),even without "extern"?

Here I have two files externdemo1.c and externdemo2.c.In the first file,I have declared and initialized a character array arr at file scope.But I have declared it in the second file externdemo2.c without the extern keyword and made use of it there in the function display(). Here are my confusions arising from it.Please answer these three:
//File No.1--externdemo1.c
#include<stdio.h>
#include "externdemo2.c"
extern int display();
char arr[3]={'3','4','7'};
//extern char arr[3]={'3','4','7'};
//extern int main()
int main()
{
printf("%d",display());
}
//File No.2--externdemo2.c
char arr[3];
int display()
{
return sizeof(arr);
}
1) Why does the program compile fine even though I have declared arr without the extern keyword in externdemo2.c?I had read that the default linkage of functions is external,but I am not sure if that's so even for variables.I only know that global variables have extern storage class.
2) What is the rigorous difference between extern storage class and extern linkage.I badly need a clarification about this.In the first file,where I have defined the array arr,I haven't used the keyword extern, but I know that it has extern storage class by default.But in the second file, isn't there any default extern ,storage class or linkage,about the global variable arr,ie, in externdemo2.c?
3) Check the commented out line in the first file externdemo1.c.Just to test it, I had used the line extern char arr[3]={'3','4','7'};.But it gives the error 'arr' initialized and declared 'extern'.What does this error mean? I have also mentioned a commented line extern int main(),but it works fine without error or warning.So why can we use extern for a function even though a function is extern by default,but not for a variable,like arr here?
Please take some time to bail me out over this.It will clear most of my lingering doubts about the whole extern thing.It will be immense help if you can answer all 3 bits 1),2) and 3). Especially 3) is eating my brains out
Main questions
Basically, because you've included the source of externdemo2.c in the file externdemo1.c.
This is the big question. Because there is no initializer, the line char arr[3]; in externdemo2.c generates a tentative definition of the array arr. When the actual definition with initialization is encountered, the tentative definition is no longer tentative — but neither is it a duplicate definition.
Regarding extern storage class vs extern linkage...Linkage refers to whether a symbol can be seen from outside the source file in which it is defined. A symbol with extern linkage can be accessed by name by other source files in which it is appropriately declared. To the extent it is defined, extern storage class means 'stored outside of the scope of a function', so independent of any function. The variable defined with exern storage class might or might not have extern linkage.
Because it is not defined with the keyword static, the array arr has extern linkage; it is a global variable.
With the commented out line uncommented out, you have two definitions of one array, which is not allowed.
I observe that you must be compiling just externdemo1.c to create a program — the compiler is including the code from externdemo2.c because it is directly included. You can create an object file from externdemo2.c. However, you cannot create a program by linking the object files from both externdemo1.c and externdemo2.c because that would lead to multiple definitions of the function display().
Auxilliary questions
I have placed both files in the [same directory]. If I don't include the second file in the first, then when I compile the first file it gives the error undefined reference to display. Since I have used extern for that function in the first file, isn't the linker supposed to link to it even if I don't include the second file? Or the linker looks for it only in default folders?
There are a couple of confusions here. Let's try dealing with them one at a time.
Linking
The linker (usually launched by the compiler) will link the object files and libraries that are specified on its command line. If you want two object files, call them externdemo1.obj and externdemo2.obj, linked together, you must tell the linker (via the build system in the IDE) that it needs to process both object files — as well as any libraries that it doesn't pick up by default. (The Standard C library, plus the platform-specific extensions, are normally picked up automatically, unless you go out of your way to stop that happening.)
The linker is not obliged to spend any time looking for stray object files that might satisfy references; indeed, it is expected to link only those object files and libraries that it is told to link and not add others at its whim. There are some caveats about libraries (the linker might add some libraries not mentioned on the command line if one of the libraries it is told to link with has references built into it to other libraries), but the linker doesn't add extra object files to the mix.
C++ with template instantiation might be argued to be a bit different, but it is actually following much the same rules.
Source code
You should have a header, externdemo.h, that contains:
#ifndef EXTERNDEMO_H_INCLUDED
#define EXTERNDEMO_H_INCLUDED
extern int display(void);
extern char arr[3]; // Or extern char arr[]; -- but NOT extern char *arr;
#endif /* EXTERNDEMO_H_INCLUDED */
You should then modify the source files to include the header:
//File No.1--externdemo1.c
#include <stdio.h>
#include "externdemo.h"
char arr[3] = { '3', '4', '7' };
int main(void)
{
printf("%d\n", display());
return 0;
}
and:
//File No.2--externdemo2.c
#include "externdemo.h"
int display(void)
{
return sizeof(arr);
}
The only tricky issue here is 'does externdemo2.c really know the size of arr?' The answer is 'Yes' (at least using GCC 4.7.1 on Mac OS X 10.8.3). However, if the extern declaration in the header did not include the size (extern char arr[];), you would get compilation errors such as:
externdemo2.c: In function ‘display’:
externdemo2.c:7:18: error: invalid application of ‘sizeof’ to incomplete type ‘char[]’
externdemo2.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]
Your program looks a bit err. To me the #include "externdemo2.c" line appears invalid.
Following is the correction I have made and it works.
//File No.1--externdemo1.c
#include <stdio.h>
extern char arr[3];
extern int display();
int main()
{
printf("%d", arr[0]);
printf("%d",display());
}
//File No.2--externdemo2.c
char arr[3]={'3','4','7'};
int display()
{
return sizeof(arr);
}
Please follow the below links for better understanding:
Effects of the extern keyword on C functions
How do I use extern to share variables between source files?
Using #include as shown will make both as one file only. You can check the intermediate file with flag -E, as in:
gcc -E externdemo1.c

Can we declare, define & assign values to a variable and use those variables in another file?

I am a beginner to C programming and I'm trying out different methods and experimenting with small programs.
I have four files. two header files and two source files. I want to:
Declare a variable (Actually two variables and a char) and a
function (from the second source file) in one header file.
Define these variables and assign values to them in a second header
file(variables from point 1).
Write a function including these two header files and using the
values from these files(point 2) in one source file (without a main-
just a function definition using the variables).
Have a main source file that invokes the function from the second
source file (from point 3.)
How do I come about this? I have included both header files in both the .c files. But when I try to compile and link it (using GCC in Linux) I get a
multiple definition ... first defined here error for all the variables.
I have looked at these answers First and Second
I didn't quite understand the answers in the Second as I'm not able to figure out how to use header guards.
I am not able to figure out how to check all of the boxes (points one through 4).
header1.h
extern int i,j; extern char c;
void ad_d();
header2.h
int j=6;int i=7;
char c='x';
fnfile.c
#include "header1.h"
#include "header2.h"
#include<stdio.h>
void ad_d()
{
i+=j;
printf("\n %d \t %c \n", i,c);
}
filemain.c
#include<stdio.h>
#include "header1.h"
#include "header2.h"
void main()
{
ad_d();
}
You can only define a variable once, that allcoates space in memory where the value will be stored. you can then declare the variable in each file (or better yet in a common header file) which will tell the compiler that a varialble of that name and type will be defined in one of the compiled files, and can be found at a later stage.
in the file where you want to define the variable use:
int my_global = 0; /* always good practice to initalize */
in other files (or a common header) use:
extern int my_global;
Now you can read or write my_global from any file where it is declared.
The header guard stuff is an attempt to move the definition and declaration into the same statement, at your level it is probably best that you get a handle on declaration vs definition before trying to play games like that.
int j=6;int i=7;
char c='x';
You don't want these in a header file, as they're definitions. Put them in the C file instead, and just include the same header in both files (with the extern declarations of the variables).
As it stands, both of your source files are trying to define these variables, which is why you get the error.

Error while compiling C code on AIX 7

SO, I have been asked to compile some legacy C code on a AIX7 (64 bit ) box.
And, I just changed the makefiles to edit the compiler that was used (from gcc to xlc_r), and the flags, from (-DAIX3 to -DAIX7).
However, thanks to this tomfoolery, I am getting an error which complains
xlc_r -c -q64 -O -DAIX -DAIX7 log.c
"log.c", line 128.7: 1506-343 (S) Redeclaration of log_write differs from previous declaration on line 140 of "lib.h".
"log.c", line 128.7: 1506-378 (I) Prototype for function log_write cannot contain "..." when mixed with a nonprototype declaration.
"log.c", line 165.7: 1506-343 (S) Redeclaration of log_errno differs from previous declaration on line 141 of "lib.h".
"log.c", line 165.7: 1506-378 (I) Prototype for function log_errno cannot contain "..." when mixed with a nonprototype declaration.
make: 1254-004 The error code from the last command is 1.
The method is question look like
extern void log_write _PROTO(( int, char *, ... ));
extern void log_errno _PROTO(( int, char *, ... ));
I want to know what the ... is, does it make for an open list of parameters? And how do I get this to run on AIX7?
An ellipsis (...) in a function declaration or definition indicates that the function accepts a variable number (zero or more) of parameters.
Back in the days when it was common to need to compile code using both pre-ANSI and ANSI-conforming compilers, a frequent approach for handling function declaration differences between the two flavors of the C language was to conditionally define a macro that could allow either ANSI-style declarations or K&R-style declarations by changing a macro definition. I suspect that the _PROTO() macro used in your example is being defined to have K&R-style declarations instead of ANSI-style declarations with prototypes, fixing this will likely address these compilation issues

Error: "expected '(' before string constant"

Working on computing the geometric mean of values in an array
The function should compute the geo mean correctly, but i'm getting a weird error message
#include <stdio.h>
#include <stdint.h>
#include <math.h>
extern "C"
double geomean(double myarray[], int count) ////error here, expected '(' before string constant
{
double geomean = 1;
double root = (1/(double)count);
int i;
for(i = 0; i < count; i++)
{
geomean = geomean * myarray[i];
}
geomean = pow(geomean, root);
return geomean;
}
extern "C" is not valid C (it's only valid in C++). Just remove it if you're working in pure C.
I am answering this question in an attempt to cover that could have been covered in more detailed answer to aid the questioner or other persons visiting this page.
Error: “expected '(' before string constant”
As mentioned in some other answer of your question, extern "C" is not valid C (it's only valid in C++). You can remove it if you're using only pure C.
However, if you (or someone else) have a mix of C and C++ source files, then you can make use of macro __cplusplus. __cplusplus macro will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file.
Thus, the same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C" when being interpreted as C++, and they should not have extern "C" when being interpreted as C (as in your case you were getting an error!).
#ifdef __cplusplus
extern "C" {
#endif
// Your prototype or Definition
#ifdef __cplusplus
}
#endif
Note: All extern "C" does is affect linkage. C++ functions, when compiled, have their names mangled. This is what makes overloading possible. The function name gets modified based on the types and number of parameters, so that two functions with the same name will have different symbol names.
If you are including a header for code that has C linkage (such as code that was compiled by a C compiler), then you must extern "C" the header -- that way you will be able to link with the library. (Otherwise, your linker would be looking for functions with names like _Z1hic when you were looking for void h(int, char)).
the first line should be: extern C;
The other option would be declaring c outside the main function without the extern keyword...

Resources