技術は記憶の彼方へと

覚えたつもりですぐに忘れるエンジニアの備忘録

【C言語】数学関数利用時のundefind referenceの解決

新卒として就職したり引っ越ししたりとバタバタでなかなかプログラムに触ってこなかったのでなかなかネタもなく更新さぼってました...
そんな中でお仕事でC言語を使うとのことでひっさびさにC言語に触れてリハビリしてますがそんなときに襲われたエラーのお話。

目次


環境


問題


発生した問題に関してはタイトルの通りです。#include <math.h>ってちゃんと記載してたんですが数学関数を使おうとするとエラーだって文句を言ってきます。
問題のコードがこちら...

#include <stdio.h>
#include <math.h>

int main(void){
        const double pi = 3.14159;
        double r = 30 * pi / 180;
        double x = 3.0;
        double y = -2.0;
        double z = 12.3;

        printf("sin(%f) = %f\n", r, sin(r));

        printf("pow(%f, %f) = %f\n", x, y, pow(x, y));

        printf("ceil(%f) = %f\n", z, ceil(z));
        printf("floor(%f) = %f\n", z, floor(z));

        return 0;
}

変数で使ってる数値は割と適当なので気にしてはいけない。

プログラム自体には特段問題はないはずなのでこれを実行してみる。

$  gcc -o Test math.c
/usr/bin/ld: /tmp/cc0VzCVR.o: in function `main':
math.c:(.text+0x68): undefined reference to `sin'
/usr/bin/ld: math.c:(.text+0x9b): undefined reference to `pow'
/usr/bin/ld: math.c:(.text+0xca): undefined reference to `ceil'
/usr/bin/ld: math.c:(.text+0xf4): undefined reference to `floor'
collect2: error: ld returned 1 exit status

なんとなくわかる気はする。mathが読めてねぇのでは?と...

ただ、mathが動くかどうかのテストでは

#include <stdio.h>
#include <math.h>

int main(void){
        printf("pow(3.0, -2.0) = %f\n", pow(3.0, -2.0));

        return 0;
}

こんなコードでエラーなく動いたんですよね...
だから余計に意味が分からなくていろいろと考えてました。

原因



結論:コンパイル時のリンカが静的ライブラリのリンク時にmathを見つけられていない

結論としては実にシンプルで上記の通り。見つけられなかったんだから使えない、実にその通りだ。
じゃあなんで変数ならだめで定数ならうまくいったのか。
これはコンパイラの実装に依存していてうまくいくこともあるようだ。だから今回のgccではたまたまうまくいった、と言ってもいいだろうと思う。
あくまでたまたま、根本的には解決していない。

どうもgccやccといった各種Cコンパイラがライブラリを捜索するのはデフォルトではlibcというものだけらしい。ただ、今回使いたかったmathはここには入っていないようだ。
なんでも関数のサイズが大きすぎるんだとかなんだとか...
そりゃ見つからないわけだ。

解決方法


デフォルトにはないならどこにあるのか。
どうもlibmというところに入っているようだ。つまりリンカにリンク作業をするときにlibmってとこに入ってるからこっちも探してって教えてやればよさそうだ。

つまり、-lオプションで教えてやればいいということになる。
実行した結果がこちら

$ gcc -lm -o Test math.c
$ ./Test
sin(0.523598) = 0.500000
pow(3.000000, -2.000000) = 0.111111
ceil(12.300000) = 13.000000
floor(12.300000) = 12.000000

エラーも吐かずに想定していた動きをしてくれた。

最後に


今回はC言語を久々にやった際に発生したエラーについて書いたわけですが、まぁリンクできないなんて思っていなかった分かなり悩んでました。
実際たまたまと書いてますが定数だと動いてしまったもんだから、余計にリンクできてないって思わなかったんですよね...

コロナの影響でいろいろバタバタしてる中で引っ越ししたりってしててなかなかブログさぼってしまいました。
今後はもう少しプログラム等と戯れながらネタ探して書いていけたらなぁなんて思ってます。
では、今回はこの辺で