{C/C++C++とCが混在したプログラムを書くとときどき定義したはずの関数がundefinedだと言われることがある。そんなときの対処法とマングルの話。その前にまずはC言語だけの場合を考える。以下のようなCのプログラムを書いてみる。puts("ok");}見てのとおり、main.cはfunc1関数を呼び出しており、foo.cはfunc1関数を定義している。main.cをコンパイルしてできたmain.oもfunc1を参照し、foo.cをコンパイルしてできたfoo.oはfunc1を定義する。オブジェクト中で使われているシンボルはnmコマンドで見ることができる。puts"U"になっているのは定義されていないもの、つまりそのシンボルを外部参照している。"T"になっているのはそのシンボルが定義されていることを意味する(正確には、"T"は「そのシンボルがテキスト(コード)セクションにある」という意味だが、細かいことは今回は関係ないので省略)。このため、main.oとfoo.oをリンクさせてやれば、func1関数の呼び出しが可能になる。./a.outokC++の場合C++の場合もCと同じような方法でシンボルの解決を行うが、Cとは違ってソースコード中の関数/変数名をそのままオブジェクトファイル中のシンボルにすることはできない。いうのは、C++では同名の関数を複数作ることができるからだ。引数の型が異なれば同じ名前を使えるし(オーバーロード)、クラスや名前空間が異なればやはり同じ名前を使える。以下のような場合を考えよう。Foo::func1(){}このソースでは、func1という名前の関数が3つ存在する。そのため、func1という名前だけでは同定することができず、正しくリンクできなくなってしまう。そのため、C++コンパイラは、引数の型やクラス・名前空間名を使って修飾された一意な名前を作成し、オブジェクトファイルにはその修飾された名前を使う。これをマングル(mangle)と呼ぶ。実際にコンパイルして見て見ると以下のようになる。_ZN3Foo5func1Evなにやら複雑な名前になっているが、よく見ると"func1"や"Foo"という文字が見える。マングルされた名前から元に戻すことをデマングルと呼び、nmコマンドでは--demangleでデマングルできる。Foo::func1()C++からCの関数を呼ぶ場合C++からCの関数を呼ぶ場合、このマングル処理が問題になる。func1(){}main.cppはC++、foo.cはCで書かれている。これをビルドしてみよう。statusと、こんな風にエラーになってしまった。エラーメッセージによれば、func1()が見つからないらしいが、それはfoo.oにあるはずだ。リンクできない理由はnmを使えば分かる。func1main.oはC++コンパイラが作ったので関数名がマングル,され"_Z5func1v"を参照しているが、foo.oはCコンパイラが作ったのでマングルされず、"func1"になっているのだ。これを解決するには、C++コンパイラに対して、「func1はCの関数だからマングルしない名前で参照せよ」と命じる必要がある。これで囲まれた中で宣言された関数はCの関数とみなされ、マングルされずに使われる。この構文はCコンパイラは理解できずエラーになる。そのため、__cplusplusマクロを使い、C++コンパイラから読まればときだけ有効になるようにする。FOO_Hこれでようやくビルドできる。}とインクルードガードはCのヘッダには必ず入れるようにしよう。{}が書かれておらず、かつそれが他人の作ったやつで変更できないような場合は、include文を囲むことで回避できる。"foo.h"}とすれば良い。Windows...2016-08-29GCC7ではエラーメッセージが改善されるらしいプログラムを書いているときには当然色々ミスをするが、GCC(gc...2016-08-28valgrindが検出するメモリリークの種類C/C++のメモリリークチェックツールと言えばvalgrindが有名だが...2013-06-01Makeでビルドオプションによって出力ディレクトリを変える前回はMakefileをヘッダファイルの依存関係に対応させてみた。(1)はてなブログをはじめよう!wagavulinさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。