why this is giving an error? [duplicate] - c

simple problem:
given the following program:
#include <stdio.h>
inline void addEmUp(int a, int b, int * result)
{
if (result) {
*result = a+b;
}
}
int main(int argc, const char * argv[])
{
int i;
addEmUp(1, 2, &i);
return 0;
}
I get a linker error...
Undefined symbols for architecture x86_64:
_addEmUp", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
seems as though it doesn't bother to compile it.
it shouldn't need to be static, I wouldn't think, based on what I have read in:
Linker error inline function (as this is in a different object, and dealing with 2 definitions rather than zero)
This is a related link, but it is c++ and I don't think it is good practice in std C to put code in the header:inline function linker error
compiler info:
cc --version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix
compilation example:
# cc main.c
Undefined symbols for architecture x86_64:
"_addEmUp", referenced from:
_main in main-sq3kr4.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocatio

Paragraph 7 of section 6.7.4 says:
Any function with internal linkage can be an inline function. 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, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.
Your file does not contain an external definition of addEmUp, and the compiler chose to use the external definition in the call in main.
Provide an external definition, or declare it as static inline.

Try adding the "-O" option to your compiler command. Inlining is turned on only when optimization is enabled.

The program causes undefined behaviour (no diagnostic required) due to 6.9/5, sometimes informally called the "one definition rule":
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.
Your program uses the identifier addEmUp while providing no external definition for it. (As mentioned already, "An inline definition does not provide an external definition for the function").
We do not need to start talking about which definition a function call calls etc. etc. The reason for ODR violations being undefined with no diagnostic required is to make it easier on the compiler writer; if this code required a diagnostic then the compiler would have to do a pass with inline optimization disabled to check for the existence of the external definition, which is a waste of time really.

Related

Why do I get a linking error with clang when inlining a function in a C program?

Why doesn't the following program compile with clang?
#include <stdio.h>
inline int f() {
return 42;
}
int main() {
printf("%d\n", f());
}
I get the following:
$ clang -o inline inline.c
Undefined symbols for architecture arm64:
"_f", referenced from:
_main in inline-975155.o
ld: symbol(s) not found for architecture arm64
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
But I can compile it with clang++ just fine. Is there some nuance between inline in C vs C++?
In C99 you need to provide an alternate (non-inline) definition of the function for when the compiler can't inline. See https://clang.llvm.org/compatibility.html#inline
One of the solutions may work for you, is to make the definition static:
#include <stdio.h>
static inline int f() {
return 42;
}
int main() {
printf("%d\n", f());
}
will work as you expect.
Here are all the options listed in the on the linked clang page:
Change add to a static inline function. This is usually the right solution if only one translation unit needs to use the function. static inline functions are always resolved within the translation unit, so you won't have to add a non-inline definition of the function elsewhere in your program.
Remove the inline keyword from this definition of f. The inline keyword is not required for a function to be inlined, nor does it guarantee that it will be. Some compilers ignore it completely. Clang treats it as a mild suggestion from the programmer.
Provide an external (non-inline) definition of f somewhere else in your program. The two definitions must be equivalent!
Compile in the GNU C89 dialect by adding -std=gnu89 to the set of Clang options. This option is only recommended if the program source cannot be changed or if the program also relies on additional C89-specific behavior that cannot be changed.
In 6.7.4 7, the C 2018 standard says an inline definition does not provide an external definition:
… An inline definition does not provide an external definition for the function…
and that a compiler may use an inline definition or an external definition:
… It is unspecified whether a call to the function uses the inline definition or the external definition.
Thus, a compiler may compile a call to f as a call to the inline definition, which will not result in a link error, or as a call to an external definition, which will result in a link error if you have not provided an external definition. The compiler’s choice may be affected by optimization switches and other settings.
The C++ standard does not have this wording (but I will leave it to others to provide additional interpretation of the C++ standard).
Very simple: Inlining does not work if you do not enable optimizations.
https://godbolt.org/z/KrWq4PGhd
To sort this problem out you need to instruct the compiler to emit not inline version as well:
extern inline int f() {
return 42;
}
Then it will work in both cases (will be inlined or not)
https://godbolt.org/z/dh3G18PqK
CLANG works exactly the same way:
https://godbolt.org/z/ssMnzf5MG
https://godbolt.org/z/ssMnzf5MG

clang behaves differently with global variables

I have these dummy piece of software made of 3 files:
test.h
int gv;
void set(int v);
test.c
#include "test.h"
void set(int x) {
gv = x;
}
main.c
#include "test.h"
#include <assert.h>
int main() {
set(1);
assert(gv == 1);
}
The code compiles and run fine in both MSVC 2019 and GCC 8, but with clang (clang-cl 11 supplied by Visual Studio 2019) fails at link time complaining about gv already defined:
1>------ Build started: Project: test, Configuration: Debug x64 ------
1>lld-link : error : undefined symbol: gv
1>>>> referenced by ...\test\main.c:6
1>>>> x64\Debug\main.obj:(main)
1>>>> referenced by ...\test\test.c:4
1>>>> x64\Debug\test.obj:(set)
1>Done building project "test.vcxproj" -- FAILED.
I understand that extern is the default storage-class specifier for objects defined at file scope, but if I explicitly specify extern to int gv, it breaks the linkage with every compiler (unless I add a definition for gv in a source file, of course).
There is something that I do not understand. What is happening?
int gv; is a tentative definition of gv, per C 2018 6.9.2 2. When there is no regular definition in a translation unit (the file being compiled along with everything it includes), a tentative definition becomes a definition with an initializer of zero.
Because this tentative definition is included in both test.c and main.c, there are tentative definitions in both test.c and main.c. When these are linked together, your program has two definitions.
The C standard does not define the behavior when there are two definitions of the same identifier with external linkage. (Having two definitions violates the “shall” requirement in C 2018 6.9 5, and the standard does not define the behavior when the requirement is violated.) For historic reasons, some compilers and linkers have treated tentative definitions as “common symbol” definitions that would be coalesced by the linker—having multiple tentative definitions of the same symbol would be resolved to a single definition. And some do not; some treat tentative definitions more as regular definitions, and the linker complains if there are multiple definitions. This is why you are seeing a difference between different compilers.
To resolve the issue, you can change int gv; in test.h to extern int gv;, which makes it a declaration that is not a definition (not even a tentative definition). Then you should put int gv; or int gv = 0; in test.c to provide one definition for the program. Another solution could be to use the -fcommon switch, per below.
The default behavior changed in GCC version 10 (and possibly Clang at some point; my Apple Clang 11 behaves differently from your report). With GCC and Clang, you can select the desired behavior with the command-line switch -fcommon (to treat tentative definitions as common symbols) or -fno-common (to cause a linker error if there are multiple tentative definitions).
Some additional information is here and here.
I understand that extern is the default storage-class specifier for objects defined at file scope
That's true but the linkage breaks because of "redefinition" of the gv symbol, isn't it?
That's because both test.c and main.c have int gv; after the preprocessor includes the headers. Thus eventually both objects test.o and main.o contain _gv symbol.
The most common solution is to have extern int gv; in the test.h header file (which tells the compiler that gv storage is allocated somewhere else). And inside the C file, main.c for example, define int gv; so that the storage for gv will be actually allocated but only once, inside main.o object.
EDIT:
Referring the same link you provided storage-class specifier, which contains the following statement:
Declarations with external linkage are commonly made available in header files so that all translation units that #include the file may refer to the same identifier that are defined elsewhere.

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.

Inline function multiple definition

I have the following three files:
inline_header.h
#ifndef INLINE_HEADER_H
#define INLINE_HEADER_H
inline int func1() {
return 1;
}
#endif
source1.c
#include "inline_header.h"
source2.c
#include "inline_header.h"
int main() {
func1();
}
When I compile just source2.c with gcc source2.c it compiles. However, when I attempt to compile with gcc source1.c source2.c I get the a multiple definition error as follows:
/tmp/cchsOaHF.o: In function `func1':
source2.c:(.text+0x0): multiple definition of `func1'
/tmp/ccEyUW0T.o:source1.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
I am compiling with gcc 4.8.4 on Ubuntu 14.04.
I've tried looking this up and found a similar question multiple definition of inline function. However in his case, the error is caused by a redefinition of his inline function. In my case, I am not redefining it (or at least not explicitly...).
When you compile source1.c into source1.o, it contains a definition of func1. Similarly, when you compile source2.c into source2.o, it also contains a definition of func1. So when you link source1.o and source2.o, you get a multiple definition error.
The reason the include guards don't prevent this is because source1.c and source2.c are each compiled separately. Include guards only help within a single compilation unit.
If this were not an inline function, you'd put a declaration in the header file:
int func1();
Then put the definition in exactly one source file.
However, you're defining the function as inline. So you need to also declare it as static so that each compilation unit gets its own copy of the function.
EDIT:
The multiple definition error is happening because you're compiling in C89 mode by default, and inline isn't part of that version of the standard. As such, it seems that gcc is basically ignoring that keyword.
If you compile in C99 or C11 mode using -std=c99 or =std=c11 with this code, you'll actually get an "undefined reference" error. Section 6.7.4p7 of the C standard states the following:
Any function with internal linkage can be an inline function. 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,and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition
What this means is that a function with only inline doesn't actually provide a definition of a function that can be called. In your case, you want to add the static storage class specifier to force a local definition in each file.
Interestingly, if you compile this code as is with -O1 and -std=c99, gcc will physically inline the function and it will compile and run cleanly.
If you wish to place this sort of function in a header, it must also be static:
static inline int func1() {
return 1;
}
This will cause the symbol to be local to each compilation unit (file), avoiding any linker errors.
Also, from the gcc manual:
When an inline function is not static, then the compiler must assume
that there may be calls from other source files; since a global symbol
can be defined only once in any program, the function must not be
defined in the other source files, so the calls therein cannot be
integrated. Therefore, a non-static inline function is always compiled
on its own in the usual fashion.

Simple C inline linker error

simple problem:
given the following program:
#include <stdio.h>
inline void addEmUp(int a, int b, int * result)
{
if (result) {
*result = a+b;
}
}
int main(int argc, const char * argv[])
{
int i;
addEmUp(1, 2, &i);
return 0;
}
I get a linker error...
Undefined symbols for architecture x86_64:
_addEmUp", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
seems as though it doesn't bother to compile it.
it shouldn't need to be static, I wouldn't think, based on what I have read in:
Linker error inline function (as this is in a different object, and dealing with 2 definitions rather than zero)
This is a related link, but it is c++ and I don't think it is good practice in std C to put code in the header:inline function linker error
compiler info:
cc --version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix
compilation example:
# cc main.c
Undefined symbols for architecture x86_64:
"_addEmUp", referenced from:
_main in main-sq3kr4.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocatio
Paragraph 7 of section 6.7.4 says:
Any function with internal linkage can be an inline function. 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, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.
Your file does not contain an external definition of addEmUp, and the compiler chose to use the external definition in the call in main.
Provide an external definition, or declare it as static inline.
Try adding the "-O" option to your compiler command. Inlining is turned on only when optimization is enabled.
The program causes undefined behaviour (no diagnostic required) due to 6.9/5, sometimes informally called the "one definition rule":
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.
Your program uses the identifier addEmUp while providing no external definition for it. (As mentioned already, "An inline definition does not provide an external definition for the function").
We do not need to start talking about which definition a function call calls etc. etc. The reason for ODR violations being undefined with no diagnostic required is to make it easier on the compiler writer; if this code required a diagnostic then the compiler would have to do a pass with inline optimization disabled to check for the existence of the external definition, which is a waste of time really.

Resources