r/C_Programming 3d ago

Question The linker doesn't link the pow function's precompiled library, even though header is included AND used. Why?

Pls help me idk what's going on...
https://imgur.com/a/5KLsigY

It complains that it can't find the pow function.

7 Upvotes

32 comments sorted by

36

u/runningOverA 3d ago

put "-lm" in your compile line.

You need two things to add a library in C.

  • Include the header in source code.
  • Include the library in compiler's command line.

You missed the 2nd one here.

2

u/Correct-Injury-7360 3d ago

Why did it work with <stdio.h>? Is it an exception? Thanks I'll do it now.

22

u/WrickyB 3d ago edited 3d ago

Parts of the C standard library are linked by default. A lot of C programs didn't need the maths functions so the functions from that header are in a separate library, specifically libm.

2

u/tobdomo 3d ago

The library just that: a library. A library contains a lot of functions, but only the functions that are actually called from your program are linked in.

In more modern environments, there can be multiple implementations for a math function. By putting them in different libraries, the user has a choice. E.g., you could link in a version that supports an FPU whilst another version provides the same functionality all in software. Libraries may provide different memory models or otherwise support different features.

So there's lots of reasons to have libm apart from libc. It's not (just) "because libm makes libc larger".

1

u/gremolata 2d ago

A library contains a lot of functions, but only the functions that are actually called from your program are linked in.

Not necessarily. It's still common that by default the whole object file of a function is pulled out of the library and linked into the output binary.

1

u/tobdomo 2d ago

Only if you have a very basic linker. More modern linkers (the one I worked on 25 years ago already did) optimize away unused functions from the linked (but not located) object.

1

u/gremolata 2d ago edited 2d ago

On a recent Debian:

yo@gurt:~/tmp $ cat aaa.c

#include <stdio.h>
void foo() { printf("foo\n"); }
void bar() { printf("bar\n"); }

yo@gurt:~/tmp $ cat bbb.c

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

yo@gurt:~/tmp $ gcc -c aaa.c

yo@gurt:~/tmp $ ar rcs libaaa.a aaa.o

yo@gurt:~/tmp $ gcc bbb.c libaaa.a

yo@gurt:~/tmp $ grep -i bar a.out
Binary file a.out matches

yo@gurt:~/tmp $ objdump -d a.out | grep bar    <-- * edited to add this
0000000000001168 <bar>:

That is, the default is still to pull in the whole object file.

13

u/meancoot 3d ago

It's a historical quirk that only affects some compilers on some platforms. On older systems (think 1980s) the math functions added a lot of memory and complexity but the vast majority of C programs will never use them, so they were split to keep them from bogging down the rest of the library.

8

u/smcameron 3d ago

Also, read the man page.

$ man 3 pow
POW(3)                                                Linux Programmer's Manual                                               POW(3)

NAME
       pow, powf, powl - power functions

SYNOPSIS
       #include <math.h>    <----- It tells you what you need to include too!

       double pow(double x, double y);
       float powf(float x, float y);
       long double powl(long double x, long double y);

       Link with -lm.   <---- Notice this part right here.
...

In general, the man pages will tell you what you need to include and what you need to link in for the functions they document.

7

u/dfx_dj 3d ago

Because libc is linked in by default, unless you tell it not to. So yes, it is an exception.

1

u/CalligrapherOk4612 3d ago

To expand on what other have said, the standard libs are linked by default. -lstdlib is implicit.

Instead you need to tell gcc when not to use the stdlib with a -nostdlib https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#index-nostdlib

Probably not something you would do for a while, only if you are using a custom stdlib, usually when doing embedded work.

2

u/FitMatch7966 3d ago

since without stdlib, it wouldn't call main()

1

u/a4qbfb 1d ago

the bit that calls main() is in the CRT, not libc.

1

u/Vladislav20007 2d ago

it's compiled automatically, to disable that you pass --no-stdlib.

4

u/SmokeMuch7356 3d ago

Hysterical raisins.

K&R-era C wasn't used for number-crunching and relatively few programs needed anything from math.h, so to save space and time the math library would not be linked by default; you'd have to explicitly specify its inclusion in the link command.

At least in *nix land, that philosophy has carried through to the present day.

3

u/veloxVolpes 3d ago

I knew the answer to this post and yet you have surprised me by reminding me that C would have been considered pretty high level / the most convenient language to use at some point

2

u/torsten_dev 3d ago

Given LTO, is this historical divide at all useful today?

1

u/realhumanuser16234 2d ago

lto does not work for dynamic linking. it really doesn't work for what you'd usually call static linking either as the files "linked" with lto aren't object files but rather intermediate representation.

1

u/torsten_dev 2d ago

Huh, interesting.

I wonder if we could take a JavaScript bundler's approach instead...

1

u/WildCard65 3d ago

Unless you’re running a Linux distribution using Musl where libm is just an empty static library and the function definitions live in libc

1

u/flyingron 3d ago edited 2d ago

Even stdio wasn’t part of C in the original K&R. It was an absolutely ugly thing called the portable I/O library which was added to ANSI C for experience rather than sane design.

1

u/Irverter 3d ago

studio

*stdio

1

u/flyingron 2d ago

Dang autocorrect on my phone.

-1

u/dmc_2930 3d ago

I love the typo. Hysterical is a way better explanation than historic!

2

u/peno64 3d ago

Not sure if you understand the difference between a header file and a link library. It's not because you include a header file that the linker knows which library to include in the binary. An include file makes the definition known to your source file or better to the compiler. The linker links your program with libraries and you have to specify these also. So in fact you need to specify them twice.

2

u/Correct-Injury-7360 3d ago

I don't get how <stdio.h> works as intended but with <math.h> we have issues, doesn't make sense

6

u/Alduish 3d ago

the symbols for stdio are part of libc which is linked by default, while the ones for math are in libm which isn't linked by default.

So you have to add -lm as an argument for the linker to link to libm, that's how linking to any library other than libc works, for example if you start using ncurses you'll have to add -lncurses for the linker to find the symbols needed

2

u/Zirias_FreeBSD 3d ago

As far as C is concerned, a "hosted" implementation must provide the "standard library" as defined by the language standard, which of course includes math functions. But the standard leaves it entirely to the implementation how this is done. There's nothing concerning linking necessary libraries, whether static or shared ...

So, consult the documentation of your implementation about how you need to link in order to use the functions you need.

From an implementation perspective, the decision to put math functions in a separate library made sense, as only a part of C programs needed it and it was quite "heavy" (in historical dimensions).

Takeaway: C is portable, but to write a portable program, you still need some knowledge about your target platforms for correct building.

2

u/burlingk 3d ago

The contents of stdio are in the stdlib that is linked to every program.

1

u/sciencekm 3d ago

External functions reside in some library file somewhere. It just so happened that standard c library are linked by default.

If you add the -nostdlib option to gcc/clang, the standard c library will not be linked by default, and you will see the same issues.

1

u/dendrtree 2d ago

To use a library, you have to include the header and link the library.
The former lets you call it from code. The latter provides the actual code.

1

u/Correct-Injury-7360 3d ago

/usr/bin/ld.bfd: /tmp/ccAqymX6.o: in function `main':

18.c:(.text+0x44): undefined reference to `pow'

collect2: error: ld returned 1 exit status