9

So I have the following code:

#include <stdio.h>

#define MAX(a,b) (a) > (b) ? a : b

int abs(int a)
{
    if (a > 0)
        return a;
    else
        return a*-1;
}

inline int avg(int a, int b)
{
    return (a+b)/2;
}

int math_max(int a, int b)
{
    return (avg(a,b)+abs(avg(a,b)-b));
}

int main(int argc, char** argv)
{
    return 0;
}

When I compile it: gcc -g test.c -o test I get:

/tmp/ccZbHEju.o: In function `math_max':
test.c:(.text+0x33): undefined reference to `avg'
test.c:(.text+0x44): undefined reference to `avg'
collect2: error: ld returned 1 exit status

I can fix this by removing the inline notation from avg, but I don't know why I'm getting undefined references if its inline - I thought the compiler was supposed to take care of that

Anyone care to explain?

** Adding more information **
For those who can't reproduce, I'm using:
gcc --version gcc (GCC) 5.3.0 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compiling this code with without linking generates the following:

[ishaypeled@arania test]$ gcc -c test.c -o ./test.o
[ishaypeled@arania test]$ readelf -s ./test.o

Symbol table '.symtab' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name  
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND   
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c  
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1   
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3   
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4  
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6  
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7  
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5  
     8: 0000000000000000    25 FUNC    GLOBAL DEFAULT    1 abs  
     9: 0000000000000019    43 FUNC    GLOBAL DEFAULT    1 max  
    10: 0000000000000044    69 FUNC    GLOBAL DEFAULT    1 math_max  
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND avg  
    12: 0000000000000089    18 FUNC    GLOBAL DEFAULT    1 main 

Which clearly shows avg as NOTYPE and UND - this is why the linker failed... I have no idea why that happens. I also examined the preprocessor output from gcc:

[ishaypeled@arania test]$ gcc test.c -E

# 5 "test.c"
int abs(int a)
{
    if (a > 0)
        return a;
    else
        return a*-1;
}

int max(int a, int b)
{
    return ((a+b)+abs(a-b))/2;
}

inline int avg(int a, int b)
{
    return (a+b)/2;
}

int math_max(int a, int b)
{
    int avg_calc = avg(a,b);
    int distance_from_avg = abs(avg_calc-a);
    int res = avg_calc+distance_from_avg;
    return res;
}

int main(int argc, char** argv)
{
# 44 "test.c"
    return 0;
}

Looks perfectly fine, avg appears before the usage in math_max.

STDC version: 201112 __GNUC__ defined

Ishay Peled
  • 2,783
  • 1
  • 23
  • 37
  • 1
    Cannot reproduce. Are you sure this exact code was in a single source file, *in this exact order*? – EOF Feb 24 '16 at 21:23
  • There shouldn't be any error if the functions are not called in the main. – Careful Now Feb 24 '16 at 21:27
  • This is generally a problem if/when GCC is compiling in `-std=c99` mode. It usually isn't by default, but perhaps things have changed in modern GCC (assuming you're using a recent version). Try adding `int avg(int,int);` *after* your initial declaration for `avg()`. – Tim Čas Feb 24 '16 at 21:30
  • @EOF: More importantly, is he using these *exact flags*? Because this usually *does not* compile in C99 or C11 mode. – Tim Čas Feb 24 '16 at 21:31
  • Addendum: Can you show me what you get with `printf("%ld\n", __STDC_VERSION__);`, and can you check if `__GNUC__` is defined? – Tim Čas Feb 24 '16 at 21:34
  • 4
    @EOF: Even if you also use the function? (note that without LTO, OP's `math_max()` function probably counts as using `avg()`!). It does not for me, with C99. See [this question](http://stackoverflow.com/questions/16245521/c99-inline-function-in-c-file/16245669). – Tim Čas Feb 24 '16 at 21:36
  • @TimČas: I'm too used to compile with `-O3`, which makes this compile... – EOF Feb 24 '16 at 21:37
  • @EOF: Probably because it removes `math_max()`, and with it the call to `avg()`, entirely. Try omitting that. As an experiment, you could try to remove its definition, that is, changing `avg()` into `int avg(int,int);` and ***removing*** the `inline avg(...){...}` part. If it still compiles that way, then it's compiling *only* because `-O3` removes every reference to `avg()`. – Tim Čas Feb 24 '16 at 21:40
  • @EOF Did you manage to reproduce? – Ishay Peled Feb 24 '16 at 21:56
  • @TimČas I updated the information you requested in the post – Ishay Peled Feb 24 '16 at 21:56
  • 2
    I think you'll find here the explanation: [undefined-reference-when-calling-inline-function](http://stackoverflow.com/questions/19068705/undefined-reference-when-calling-inline-function) – cwschmidt Feb 24 '16 at 22:31
  • 1
    Have you tried adding `static` before `inline`? – Fiddling Bits Feb 24 '16 at 22:33
  • 1
    This is the behavior of a language standard and a compiler without a 1-800 support phone number :) C99 requires you to explicitly state which TU contains the definition of the inline function. That requires the highly intuitive `extern inline int avg(int a, int b);` in your source code file. – Hans Passant Feb 24 '16 at 22:53
  • @HansPassant: So both `static inline` or `extern inline` will work, but plain `inline` is parsed, compiled and ignored? – rodrigo Feb 24 '16 at 22:58
  • 1
    It is not ignored, that would cause a compile error. It doesn't get linked. This only ever makes sense when you are a member of an ISO committee that finds a compromise by making everybody equally unhappy. – Hans Passant Feb 24 '16 at 23:10
  • @HansPassant. The body of the plain inline function is ignored, it works just as a prototype for the function. In fact, I've replaced the inline function with a function prototype and the generated code is identical. – rodrigo Feb 24 '16 at 23:26
  • I accepted the duplicate suggestion as the answer (or at least the confirmation) exists in the proposed DUP, but I really don't understand the motivation behind this decision, which is actually what I'm asking – Ishay Peled Feb 25 '16 at 13:49

0 Answers0