Duplicate global variable - c

I need to use a global variable in multiple translation units, so I put
int g_exit_status;
in a header file and included that header in my source files. The default value for global variables is zero, but I need to use a specific value. I tried to specifying a value (e.g. 90), but then I received this error while compiling:
duplicate symbol '_g_exit_status' in:
/var/folders/zz/zyxvpxvq6csfxvn_n0000kch0004l4/T/main-422e60.o
/var/folders/zz/zyxvpxvq6csfxvn_n0000kch0004l4/T/parsing-328bc4.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [minishell] Error 1

The line
int g_exit_status;
is a tentative definition, which will act as a definition unless that variable is defined somewhere else in the same translation unit (i.e. in the same .c file). In the latter case, it will instead act as a declaration.
The line
int g_exit_status = 90;
is a definition.
The line
extern int g_exit_status;
is a declaration.
A definition is also a declaration, but not vice-versa.
You must declare the variable g_exit_status in all translation units in which it is used. However, according to the one-definition rule, you must define it in exactly one translation unit. You appear to be violating this rule by putting a definition inside a header file that is included by multiple translation units.
For the reasons stated above, the declaration
extern int g_exit_status;
should be inside the header file, but the definition
int g_exit_status = 90;
should only be inside a single .c file, in order to not violate the one-definition rule.

Related

Global variables initialization in C header file

I was wondering why declaring a global variable in a header file which is included in multiple source in C was working
#ifndef INC_MAIN_H_
#define INC_MAIN_H_
int my_var;
#endif
But assigning it a default value does not work:
#ifndef INC_MAIN_H_
#define INC_MAIN_H_
int my_var = 0;
#endif
It shows multiple compiling errors in each files where I include this main.h
multiple definition of `my_var'; app/src/testfile.o:app/inc/main.h:4: first defined here
I know declaring global variables this way is not the best practice, but I can't figure out why adding an assignation would cause compiling errors and I can't find clear answers about it.
With the build tools and switches you are using, int my_var; acts mostly like a declaration that is not a definition. Multiple declarations of an object identifier are allowed.
int my_var = 0; is a definition. There should be only one definition.
Due to the history of C use and development, int my_var; is technically a tentative definition. If there is no regular definition of my_var in the translation unit (the source file being compiled, including all the files it includes), it acts as a regular definition.
However, then when you have this in a header file that is included in multiple source files, you have multiple definitions. When there are multiple definitions of the same object identifier with external linkage, the C standard does not define the behavior.
When there are multiple regular definitions, your build tools report an error. However, they treat definitions that came from tentative definitions differently: They allow them and coalesce them into a single definition. Again, this is due to the history of how C developed and was used. Also, this behavior changed in GCC recently. Prior to GCC version 10, tentative definitions were coalesced by default, as described above. With GCC 10 and later, tentative definitions are not coalesced, and multiple definitions will result in an error. The old behavior can be requested with the switch -fcommon.
To avoid tentative definitions, you should declare the identifier in the header as extern int my_var;, which is just a declaration and not a tentative definition, and you should have exactly one source file containing int my_var = 0;, which is a regular definition and not a tentative definition.
Additional information is here, here, and here.

2 questions about header files and errors in C

If i have a header file in which i declare and define a function, and i include the header in a source file, will it return an error? and if yes which one?
I tried doing it and it worked but when someone else tried it on his PC, it didn't.
so in which step did the problem occur? is it the pre-processing or linking part?
If I define the same function twice (twice in the source file or once in the header and another in the source), what type of error is that?
I need to know it for an exam but couldn't find answers myself
I think you should first gather some information about the subject
of linkage.
Then you should do some research on header file descriptions.
Finally, you should learn the undefined behavior.
Linkage
Linkage 2
Header File Create
Undefined Behavior / UB
If i have a header file in which i declare and define a function, and i include the header in a source file, will it return an error? and if yes which one? I tried doing it and it worked but when someone else tried it on his PC, it didn't. so in which step did the problem occur? is it the pre-processing or linking part?
It depends. If you don't have any include guards around the function definition and the file gets #included more than once within the same translation unit, or if the name of the function defined in the header conflicts with another variable or function name defined elsewhere in the source, then yes you'll get some kind of duplicate or conflicting definition error. If nothing in the header conflicts with other code, you won't. Without knowing the details of your code or your friend's code, there's really no way to answer definitively.
Short answer is "don't do that" - don't put function or variable definitions in header files. That way you avoid this kind of problem completely.
If I define the same function twice (twice in the source file or once in the header and another in the source), what type of error is that? I need to know it for an exam but couldn't find answers myself
Most compilers call it a "duplicate definition" error. There's no formally defined name for it. Here's the relevant text from the C language definition:
6.9 External definitions
...
Constraints
...
3 There shall be no more than one external definition for each identifier declared with
internal linkage in a translation unit. Moreover, if an identifier declared with internal
linkage is used in an expression (other than as a part of the operand of a sizeof or
_Alignof operator whose result is an integer constant), there shall be exactly one
external definition for the identifier in the translation unit.
...
Semantics
...
5 An external definition is an external declaration that is also a definition of a function
(other than an inline definition) or an object. If an identifier declared with external
linkage is used in an expression (other than as part of the operand of a sizeof or
_Alignof operator whose result is an integer constant), somewhere in the entire
program there shall be exactly one external definition for the identifier; otherwise, there
shall be no more than one.161)
161) Thus, if an identifier declared with external linkage is not used in an expression, there need be no
external definition for it.
C 2011 Online Draft
The rule of thumb - do not place any code (ie function definitions) or variable definitions in the header files.
There are some possible exception (for example static inline functions).
Header files:
Function dclariations, type declaration and extern object definitions.
Source files:
Function bodies and data definitions.

Architecture clash? symbol(s) not found for architecture x86_64 on mac

I'm trying to install a C library: ssht
I've set up the makefile and it's definitely finding the dependencies. When I make it using gcc, however, I get some warnings:
In file included from ../ssht/src/c/ssht_core.c:23:0:
../ssht/src/c/ssht_core.c: At top level:
../ssht/src/c/ssht_sampling.h:39:20: warning: inline function ‘ssht_sampling_ind2elm’ declared but never defined
extern inline void ssht_sampling_ind2elm(int *el, int *m, int ind);
And then when I make the test for the code I get the error:
"_ssht_sampling_elm2ind", referenced from:
_ssht_test_gen_flm_complex.constprop.1 in ssht_test.o
_ssht_test_gen_flm_real in ssht_test.o
_ssht_test_gen_lb_flm_real in ssht_test.o
_ssht_test_gen_flm_complex in ssht_test.o
_ssht_test_gen_lb_flm_complex in ssht_test.o
_main in ssht_test.o
_ssht_core_mwdirect_inverse in libssht.a(ssht_core.o)
...
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
make: *** [../ssht/bin/c/ssht_test] Error 1
I've haven't been able to find any solutions that I could understand. By the way my gcc version is:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-apple-darwin14.4.0/5.1.0/lto-wrapper
Target: x86_64-apple-darwin14.4.0
Configured with: ../gcc-5.1.0/configure --enable-languages=c++,fortran
Thread model: posix
gcc version 5.1.0 (GCC)
I've tried installing as a 32 bit installation with -m32 to see if that changed things, but I get the same error with i386 instead of x86_64.
I have installed it on a Linux machine that I also have access to with a makefile which is identical except for the location of one of the dependencies.
Please help!
It appears that the code is broken, and the warning that you present is indeed a good clue. The standard specifies:
For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function [...].
[C2011, 6.7.4/7]
The warning signals a violation of the cited restriction: the header file indicated in the warning contains the given function declaration, which bears inline and extern specifiers. Because of the inline specifier, C requires that every translation unit in which that declaration appears also provide a definition; since it appears in a header file, that applies to every source file that includes that header. File ssht_core.c includes the header but does not provide a definition.
Examination of the source shows that the designated function is defined only in file ../ssht/src/c/ssht_sampling.c, but that that file does not include the corresponding header. When a C source file has a corresponding header, it is customary and useful for it to include that header, for that helps catch discrepancies between declarations. It is not obligatory to do so, however, so that omission is not wrong in itself.
In this case, however, the only declaration of ssht_sampling_ind2elm() in ssht_sampling.c is its definition, and that bears an inline specifier without extern. The second part of the above-quoted section of the standard therefore applies: the translation unit corresponding to that file does not provide an external definition of the function. That is, the definition it provides is only visible from within the same translation unit, not from others, such as the one associated with ssht_core.c.
The intention appears to be to provide a function definition in one file that can be inlined in other files, but that is not allowed, nor does it really make sense. I'd file a bug report with the library's author. One possible resolution would be to make ssht_sampling.c include its own header; that would not resolve the warning, but it ought to fix the linkage problem. You could clear the warning by also removing the inline specifiers from the function declaration in the header. Alternatively, you could remove the inline specifiers from the function in both the header and the main source, without changing which headers are included in which file.

if global variable have default external linkage then why can't we access it directly in another file?

I have gone through following questions:
Global variable in C are static or not?
Are the global variables extern by default or it is equivalent to declaring variable with extern in global?
Above links describe that if we define global variable in one file and haven't specified extern keyword they will be accessible in another source file because of translation unit.
Now I have file1.c in that have defined following global variable and function:
int testVariable;
void testFunction()
{
printf ("Value of testVariable %d \n", testVariable);
}
In file2.c have following code
void main()
{
testVariable = 40;
testFunction();
}
Now I am getting error: 'testVariable' undeclared (first use in this function) -- why?
Note: both files are used in same program using makefile.
As per my understanding both function and global variable have default external linkage. So function we can use directly by it's name in another file but variable can't why?
Can any one have idea?
EDIT:
From the below answer i get idea that like in case of function old compiler will guess and add an implicit declaration but in case of variable it can't. Also C99 removed implicit declaration but still I am getting warning in C99 mode like:
warning: implicit declaration of function ‘testFunction’.
Now have gone through below link:
implicit int and implicit declaration of functions with gcc compiler
It said that compiler take it as diagnostic purpose and not give error. So compiler can process forward.
But why in case of variable it can't process further? Even in case of function if compiler proceed and if actual definition not there then at linking time it will fail. So what's benefit to move forward??
There are two things in play here: The first is that there is a difference between a definition and a declaration. The other thing is the concept of translation units.
A definition is what defines the variable, it's the actual place the variable exists, where the compiler reserves space for the variable.
A declaration is needed for the compiler to know that a symbol exists somewhere in the program. Without a declaration the compiler will not know that a symbol exists.
A translation unit is basically and very simplified the source file plus all its included header files. An object file is a single translation unit, and the linker takes all translation units to create the final program.
Now, a program can only have a single definition, for example a global variable may only exist in a single translation unit, or you will get multiple definition errors when linking. A declaration on the other hand can exist in any number of translation units, the compiler will use it to tell the linker that the translation references a definition in another (unknown at time of compilation) translation unit.
So what happens here is that you have a definition and a declaration in file1.c. This source file is used as input for one translation unit and the compiler generates a single object file for it, say file1.o. In the other source file, file2.c, there is no definition nor any declaration of the global variable testVariable, so the compiler doesn't know it exists and will give you an error for it. You need to declare it, for example by doing
extern int testVariable; // This is a declaration of the variable
It's a little more complicated for the function, because in older versions of the C standard one didn't have to declare functions being used, the compiler would guess and add an implicit declaration. If the definition and the implicit declaration doesn't match it will lead to undefined behavior, which is why implicit function declarations was removed in the C99 standard. So you should really declare the function too:
void testFunction(void); // Declare a function prototype
Note that the extern keyword is not needed here, because the compiler can automatically tell that it's a function prototype declaration.
The complete file2.c should then look like
extern int testVariable; // This is a declaration of the variable
void testFunction(void); // Declare a function prototype
void main()
{
testVariable = 40;
testFunction();
}
When compiler copes with file2.c it knows nothing about existence of testVariable and about its type. And as result it can't generate code to interact with such object. And purpose of line like
extern int testVariable;
is to let compiler to know that somewhere such object exists and has type of int.
With functions we have no such problem because of next rule - if function is not defined - compiler assumes that it is defined somewhere like
int testFunction() { ... }
So you can pass any number of any arguments to it and try to obtain int return value. But if real function signature differs - you'll get an undefined behafiour at runtime. Because of this weakness such approach is considered as bad practice, and you should declare proper function prototype before any call to that func.

c code: how to detect duplicate function declarations

Is there a FLAG setting in makefile to detect duplicate function declarations?
Duplicate function declarations in a header file are found, but compiler doesn't report it even FLAG is set as "warning as error".
Does this bring any implicit problem?
You're trying to solve a problem that doesn't exist. There is generally no problem with duplicated function declarations, so there is no reason for a compiler to diagnose them.
A C compiler will typically diagnose situations, in the same compilation unit, where a function is declared in more than one way (e.g. two declarations of the same function with different return type or argument types).
Duplicate function definitions (a particular type of function declaration - which implements the function) are a problem. Practically, a compiler will give warnings or errors when multiple definitions of a function occur in a compilation unit. A linker will also report cases where a function is defined in more than one compilation unit - the exceptions being functions that are either inline or static (local to its compilation unit).
Duplicate function declarations are NOT a problem so why compiler need to report about it as a problem?
This scenario is really common:
source 1:
//definition
int func(void) {
...
}
source 2:
//declaration
extern int func(void);
source 3:
extern int func(void); //duplicate with source 2
I don't like using extern, especially for functions. Declare your function in a single header file and then include that header file in the other compilation units. If the function is only used by a single compilation unit, declare it as static with the .c file itself.

Resources