Simple C inline linker error
Asked Answered
M

3

9

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
Mose answered 24/5, 2013 at 17:26 Comment(3)
which command you used to compile?Plethoric
What compiler are you using?Cuticle
it is clang in xcode 4.6.2Mose
P
11

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.

Panga answered 24/5, 2013 at 17:54 Comment(4)
static inline didn't work (at least not in the real project; didnt try sample one)... I found a Objective-C specific macro that does work, I am in the process of updating.Mose
static inline ought to work, though. Can you boil it down far enough that the linker error remains but the code is small enough for SO?Panga
It ought to work in the real project too if it's used in only one file. Well, you always have the option to provide an external definition to fall back to.Panga
here is the clang reference detailing the difference: clang.llvm.org/compatibility.html#inlineMose
R
2

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

Ravin answered 24/5, 2013 at 17:45 Comment(2)
that does take the linker error away, but shouldn't it just ignore the keyword if it cant inline... as it is just a hint anywayMose
That's what GCC does. Clang tries to comply with C99, which has a slightly different interpretation seems like, which is why you are running into this issue. clang.llvm.org/compatibility.html#inlineRavin
G
0

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.

Gadmon answered 28/8, 2020 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.