0

I have 2 C source files:


file1.c:

#include <stdio.h>

void masp(double);

int main()
{
    masp(1.6);
    return 0;
}

file2.c:

#include <stdio.h>

inline double square(double x) 
{ 
    return (int) (x * x + 0.5); 
}

void masp(double w)
{
    double kw = square(w);
    printf("%.2f\n", kw);
    return;
}

the compile command is: gcc file1.c file2.c -o files


why do I get an error:

Undefined symbols for architecture x86_64: "_square", referenced from: _masp in ccMowbTf.o

XMan
  • 29
  • 3

3 Answers3

1

OP's function is declared as inline double square(double); (actually declared as part of the function definition in OP's code) and has a definition in the same translation unit. Because the function does not have internal linkage (i.e. it was not declared static, and was not explicitly declared extern, the inline function definition does not constitute an external definition of the function. For a call to a function not declared with internal linkage (i.e. not declared static), the compiler is free to use an inline definition of the function or to call the external function. In OP's case, the compiler chose to call the external function, but no definition of the function with external linkage has been provided, so the program failed to link.

There are three possible solutions:

  1. Either: declare the function as static inline so that the function definition is an inline function with internal linkage. The compiler is free to translate calls to the function as an actual function call or as an inline function call, with the inline keyword acting as a hint to the compiler that inline calls are preferred by the programmer.
  2. Or: provide an external definition of the function. That can be done either by duplicating the function definition without the inline specifier, or by explicitly adding the extern specifier to the existing inline definition (declaring it as extern inline).
  3. Or: remove the inline specifier to turn the function definition into an external function definition.

For reference, see C17/C18 section 6.7.4 paragraphs 6 and 7 and footnotes 140, 141 and 142:

  1. A function declared with an inline function specifier is an inline function. Making a function an inline function suggests that calls to the function be as fast as possible.140) The extent to which such suggestions are effective is implementation-defined.141)
  2. 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.142)

140) By using, for example, an alternative to the usual function call mechanism, such as “inline substitution”. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.
141) For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration.
142) Since an inline definition is distinct from the corresponding external definition and from any other corresponding inline definitions in other translation units, all corresponding objects with static storage duration are also distinct in each of the definitions.

Ian Abbott
  • 15,083
  • 19
  • 33
0

Using GCC to compile inline function you need to enable optimizations:

https://godbolt.org/z/bG6s458ef

enter image description here

or to define it as extern (to add an external linkage):

extern inline double square(double x) 
{ 
    return (x * x + 0.5); 
}

or make it static

static inline double square(double x) 
{ 
    return (x * x + 0.5); 
}

https://godbolt.org/z/qx1q6xM1K

enter image description here

BTW it is not necessary to have two files to reproduce this behaviour: https://godbolt.org/z/3heanfWT3

enter image description here

0___________
  • 60,014
  • 4
  • 34
  • 74
  • It wasn't me, but I guess it could do with an explanation. Perhaps quoting the C standard would help. – Ian Abbott Mar 15 '23 at 10:04
  • 1
    `static inline` works too without optimization and _maybe could_ be what the OP had in mind – Ingo Leonhardt Mar 15 '23 at 10:04
  • Thank you very much, now I know how to fix the issue. But I also want to know why the inline function square can not work? Can you give me more detailed explanation? Thank you very much. – XMan Mar 15 '23 at 10:05
  • 1
    I'm surprised by this. I thought `inline` was an hint that would have been ignored without optimization. Do you have further info on why marking it `inline` makes the function unavailable also in the same translation unit? – Costantino Grana Mar 15 '23 at 10:12
  • @CostantinoGrana See my answer or the "Function Specifiers" section of the C spec (C99 onwards) for the semantics of `inline`. – Ian Abbott Mar 15 '23 at 13:24
-1

By stating that the function is inline, you are hinting the compiler that you want it "copy and paste" the function into other functions. enter image description here

This leads the compiler to not actually define a new function for the square function, but instead it just pastes it's implementation in the masp function.

To fix this issue, you can either:

  1. Remove the inline directive.
  2. Move the inline function to a header file and include it from both files.
gkpln3
  • 1,317
  • 10
  • 24
  • 1
    This answer does answer the question and it is invalid – 0___________ Mar 15 '23 at 09:49
  • Why not? I've tested it. – gkpln3 Mar 15 '23 at 09:52
  • He wants `inline` function to work. Removing `inline` you do not answer the question. Moving to the header does not change anything. You simply do not understand the issue – 0___________ Mar 15 '23 at 09:53
  • You can't get `inline` to work when you have the function declared in just one compilation unit, that's why I suggest to move the function to a third header file and include it from both. – gkpln3 Mar 15 '23 at 09:54
  • Thank you very much, now I know how to fix the issue. But I also want to know why the inline function square can not work? Can you give me more detailed explanation? Thank you very much. – XMan Mar 15 '23 at 10:05
  • I'm sorry, I just realized that you did not use the `square` function in `file1.c`, my answer is incorrect. it seems like the compiler really doesn't apply the `inline` optimization unless you have the optimization flag on, which for some reason adds an actual call to the function, but omits the actual function from being inserted into the final executable. – gkpln3 Mar 15 '23 at 16:02