• ベストアンサー
  • 暇なときにでも

ヘッダファイルの外側にメンバ関数を定義する時のinline指定について

main.cpp、DUT.cppを分割コンパイルした場合、リンク時に main.o(.text+0x0): In function `DUT::FuncA()': <省略>/DUT.h:12: multiple definition of `DUT::FuncA()' DUT.o(.text+0x0):<省略>/DUT.h:12: first defined here collect2: ld returned 1 exit status とエラーが出ます。FuncA関数をインライン指定するとリンクエラーはなくなります。 インライン指定しないと関数の実体がDUT.cpp/main.cppコンパイル毎に生成され、リンク時に衝突してしまう感覚はなんとなくわかるのですが、インライン指定時にFuncA関数の中身はどこに存在しているのでしょうか。 nm/objdumpで見ても見つかりません。 どういうメモリ構造故、インライン指定時には問題が起きていないのか、どこにFuncA関数の実体はあるのかを教えていただけないでしょうか。 // DUT.h #ifndef TLM_DUT_H #define TLM_DUT_H class DUT{ public: void FuncA() ; int ValB ; } ; inline // インライン指定しないとコンパイルエラー void DUT::FuncA(){ ... } #endif // DUT.cpp #include "DUT.h" // main.cpp #include "DUT.h" int main( int, char** ){ return 0; } % make g++ -g -Wall -c DUT.cpp g++ -g -Wall -c main.cpp g++ -g -Wall -o run.x DUT.o main.o 2>&1 | c++filt main.o(.text+0x0): In function `DUT::FuncA()': <省略>/DUT.h:12: multiple definition of `DUT::FuncA()' DUT.o(.text+0x0):<省略>/DUT.h:12: first defined here collect2: ld returned 1 exit status

共感・応援の気持ちを伝えよう!

  • 回答数4
  • 閲覧数1319
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • 回答No.2
  • jacta
  • ベストアンサー率26% (845/3158)

inline指定子を付けた場合でも、関数はデフォルトでは外部結合になります。そして、インライン置換されなかったインライン関数(例えば、再帰呼出しを行ったり、インライン関数へのポインタを取得した場合)や、インライン関数の中で定義された静的記憶域期間を持つオブジェクトは、リンク時に一箇所にまとめられます。 実際にコンパイル結果を調べたり、リンク後にnmを使って関数が配置されたアドレスを調べれば分かります。

共感・感謝の気持ちを伝えよう!

関連するQ&A

  • makefileの書き方

    makefileを書いたのですが、コンパイルしたあとに、main.cppの内容を変更してから、またmakeってタイプして変更した箇所が反映されません。どこがおかしいでしょうか?よろしくお願いします。 program : main.o g++ -o program main.o main.o : main.cpp g++ -Wall -c main.cpp DeleteObj: rm main.o

  • C言語でヘッダファイルにグローバル変数を宣言する

    main.hに static int a; と記述し、main.cで #include "main.h" [省略] a=10; のように使用して、-Wallをつけてコンパイルすると、main.cで使用しているにも関わらず、 'a' defined but not used という警告が表示されます。 同様に、関数においても、ヘッダファイルでstaticをつけると ‘&#65374;’ declared ‘static’ but never defined と警告されます。 静的グローバル変数などは、ソースファイル内で宣言しなければいけないのでしょうか?ヘッダファイル内で宣言しても警告が出ないような方法はありますか?

  • linuxでリンクを貼るには

    linuxでリンクを貼るには 本に書いてある通りにプログラムをつくったのですが、 うまくコンパイルできません。 本で書いてあるのはwindowsのvisual C++で、 僕の使っている環境はlinuxのg++です。 コンパイルした結果を以下に示します。 -- ファイル名:myfunc.h //declaration of the max function int max(int x, int y); -- ファイル名:myfunc.cpp //a definition of the max function int max(int x, int y) { if(x > y) return x; else return y; } -- ファイル名:sample10.5.cpp #include <iostream> #include "myfunc.h" using namespace std; int main() { int num1, num2, ans; cout << "Please input the 1st integer.\n"; cin >> num1; cout << "Please input the 2nd integer.\n"; cin >> num2; ans = max(num1, num2); cout << "The maximum value is " << ans << '\n'; return 0; } -- bash-2.05b$ g++ myfunc.cpp /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/../../../crt1.o(.text+0x18): In function `_start': : undefined reference to `main' collect2: ld はステータス 1 で終了しました -- bash-2.05b$ g++ sample10.5.cpp /tmp/ccWJNOkX.o(.text+0x6c): In function `main': : undefined reference to `max(int, int)' collect2: ld はステータス 1 で終了しました

その他の回答 (3)

  • 回答No.4
  • rinkun
  • ベストアンサー率44% (706/1571)

実際の挙動はコンパイラ次第でしょうけど、インライン関数で呼び出しがなければ完全になくなっていても不思議ではないですね。

共感・感謝の気持ちを伝えよう!

  • 回答No.3
  • jacta
  • ベストアンサー率26% (845/3158)

混乱するといけませんんで、念のため指摘しておきます。 #1の方が書かれている > static宣言された場合と同じくファイルスコープになるので の部分ですが、static指定子を付けた場合は内部結合になるのであって、ファイルスコープになるのではありません。 また、C++にはファイルスコープというのは存在しません。C++にあるのは、名前空間有効範囲であって、明示的にnamespaceで囲まれていない部分は、大域的名前空間有効範囲になります。

共感・感謝の気持ちを伝えよう!

  • 回答No.1
  • rinkun
  • ベストアンサー率44% (706/1571)

インライン指定というのは元々、関数を呼び出す部分に関数の中身を展開するように指定するものです。 従って、インライン指定したメンバ関数は、インライン指定が適用されれば、そのメンバ関数を呼び出している部分にそれぞれ展開されています。 ただしインライン指定は必ず適用されるとは保証されてません。関数が大きすぎる場合などインライン展開が効率的でない場合には展開されません。 しかしその場合でもインライン指定した関数はstatic宣言された場合と同じくファイルスコープになるので、リンク時に衝突することはありません。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

回答ありがとうございます。 インライン・メンバ関数を呼び出しているメンバ関数に展開されるとの事ですが、質問内容に書いた記述の場合は、呼び出しているメンバ関数はいない事になるのですが、この場合は、(最適化等で)実体はなくなるのでしょうか。 nm/objdumpでインライン・メンバ関数が見当たらず。。

関連するQ&A

  • 関数ポインタの型をtypedefしたとき

    C言語において、関数ポインタの型をtypedefで作ると、 typedef int (*MyFunc)(int*,int*); と宣言でき、関数ポインタの変数は、 int FuncA(int* a, int* b) { ~ } void main_loop() { MyFunc pf = FuncA; ~ (*pf)(pa,pb); } というように使うと思います。 ここで疑問なのですが、この実際に呼び出される関数、FuncAの定義に、typedef(ここではMyFunc)を使えないものでしょうか? 同じことを2回やっているようで、無駄に思えてしまいます。

  • MinGWのg++で分割コンパイルエラー

    MinGW環境でC++の勉強を始めました。 簡単なサンプルのコンパイルをしてみたのですが、ソースファイルを一括してコンパイルすると問題ないのですが、個別にコンパイルしようとするとエラーがでてしまいまいます。 原因や対処法をご存じの方がいらっしゃいましたらご教示下さい。 一括でコンパイルすると問題なし bash-3.1$ g++ -Wl,--enable-auto-import main.cpp point.cpp -lstdc++ 個別にコンパイルしようとした場合 bash-3.1$ g++ -Wl,--enable-auto-import -o main.o main.cpp C:\DOCUME~1\user\LOCALS~1\Temp\ccZrVmLp.o:main.cpp:(.text+0x16): undefined reference to `Point::Point()' C:\DOCUME~1\user\LOCALS~1\Temp\ccZrVmLp.o:main.cpp:(.text+0x32): undefined reference to `Point::Point(int, int)' C:\DOCUME~1\user\LOCALS~1\Temp\ccZrVmLp.o:main.cpp:(.text+0x3e): undefined reference to `Point::println()' C:\DOCUME~1\user\LOCALS~1\Temp\ccZrVmLp.o:main.cpp:(.text+0x4a): undefined reference to `Point::println()' collect2: ld returned 1 exit status ※ -Wl,--enable-auto-importは、他の警告を消すために入れました、無くても質問の問題に変化はありませんでした。 サンプルソース ---main.cpp--- #include<iostream> #include "point.h" using namespace std; int main(){ Point p1,p2(4,5); p1.println(); p2.println(); return 0; } ----------- ---point.h--- class Point { private: int x, y; static int count; public: Point(); Point( int, int ); void set( int, int ); void println(); }; ------------- ---point.cpp--- #include<iostream> #include"point.h" using namespace std; int Point::count; Point::Point(){ this->x = this->y = 0; ++count; } Point::Point(int ax, int ay){ this->x = ax; this->y = ay; ++count; } void Point::set( int ax, int ay ){ this->x = ax; this->y = ay; } void Point::println(){ cout << "Point(" << x << "," << y << ")" << endl; } ----------- bash-3.1$ g++ -v Using built-in specs. COLLECT_GCC=D:\MinGW\bin\g++.exe COLLECT_LTO_WRAPPER=d:/mingw/bin/../libexec/gcc/mingw32/4.5.0/lto-wrapper.exe Target: mingw32 Configured with: ../gcc-4.5.0/configure --enable-languages=c,c++,ada,fortran,obj c,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgo mp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-r untime-libs --disable-werror --build=mingw32 --pref

  • CからC++の関数呼び出し

    CからC++の関数を呼び出して値を取得したいのですが、コンパイルエラーになってしまいます。 呼び出す関数内でさらに同じクラスの関数を呼び出して値をreturnしたいだけなのですが、 ご教示願います。 ソースは下記のような感じです。 Cソース(AAA.c) main(){ ・・・・・ if ( funcA() ){ ・・・・ } } C++ソース(BBB.cpp) int clsB::funcB { return iflg; } extern "C" { int funcA() { return funcB(); } } ※上記externは特に何かの関数内に書いているわけではありません。 C++ヘッダ(BBB.hpp) class clsB : public XXX { private: int iflg; ・・・・ public: int funcB(); ・・・・ } 上記にコンパイルすると、 externしている箇所でfuncBはスコープにありません?のようなエラーが出てしまいます。 ラッパ関数を使って使用するなどと聞いたのですが、やり方がいまいちわかりません。 どうか教えていただけますでしょうか。 また、他にやり方があるかと思いますが、いいやり方があれば教えていただけると幸いです。 以上です、よろしくお願いいたします。 不足内容あれば指定願います。

  • Mac上でのg++についての質問

    Mac Book Air 2011年度夏版(最新のやつです) Mac OSX 10.7.3 最新のXcode導入後の環境です Desktop下に保存しているmain.cppをg++でコンパイルしようとしてエラーがでます ターミナルで下記のとおりにリターンすると cd Desktop/ g++ -Wall main.cpp -bash: g++: command not found というエラーが表示されます g++が正しくMacにインストールされていないのでしょうか? Xcodeはapp storeからinstallしました。Xcodeでは問題なく実行はできます。

  • octaveのコンパイルオプション

    MATLABのクローンのoctaveを, C++のライブラリとして利用したいと考えているのですが, コンパイルが上手くいきません. プログラムは以下のような単純なものです. --------- begin of hello.cpp ------------------ #include<iostream> #include<octave/config.h> #include<octave/Matrix.h> int main(){ Matrix m(2,2,1.0); cout<<"hello octave !"<<m; return 0; } --------- end of hello.cpp -------------------- 次のようなコンパイルオプションでコンパイルしています. > g++ -I/usr/include/octave-2.1.35/ -L/usr/lib/octave-2.1.35 \ -loctave -lcruft -loctinterp -lreadline -lcurses -llapack \ -lblas -ldl -lg2c -L/home/pippin/name/.redhat/SOURCES/octave-2.1.35/kpathsea \ -lkpathsea hello.cpp すると,次のようなエラーメッセージを返されます. /tmp/ccuvk2IV.o: In function `main': /tmp/ccuvk2IV.o(/text+0x2c): multiple definition of `main' /usr/lib/gcc-lib/i386-redhat-linux/2.96/libg2c.a(main.o)(.text+0x0): first definition here /usr/bin/ld: Warning: size of symbol `main' changed from 58 to 174 in /tmp/ccuvk2IV.o collect2: ld returned 1 exit status エラーメッセージから解するに,libg2c.aでもmain関数が定義されているため, hello.cppのmain関数とかぶるという様な事だと思うんですが,ライブラリに main関数が定義されているというのも変な話です. ちなみに,コンパイルした環境は, OS: redhat linux 7.3 octave version 2.1.35 gcc version 2.96 このタイプのエラーを回避する方法を知っておられる方は, 回答の方よろしくお願いします.

  • C言語で、記憶クラス指定子extern・staticを関数に指定

    C言語の本に、「関数の定義と呼び出す側が別ソースファイルの場合、プロトタイプはヘッダーファイルに書き、定義側と呼び出し側の両方でインクルードしましょう」ということが書かれていました。 例えば、 ===code1a.c=== extern void funcB(int); static void funcA() { funcB(1); } ===code1b.c=== void funcB(int a) { printf("%d\n",a); } このような場合には、もしcode1b.cの中の関数funcBに引数を追加した場合、再コンパイルしても気づかないのでよくない。 そこで、次のようにヘッダーファイルを作り、プロトタイプはそこに書くべきだ。 ***code2b.h*** extern void funcB(int); ***code2a.c*** #include "code2b.h" static void funcA() { funcB(1); } ******code2b.c**** #include "code2b.h" void funcB(int a) { printf("%d\n",a); } 記述は以上のようなことです。 #include "code2b.h" とは、 extern void funcB(int); が書いてあるのと同じだと思います。 私が思ったのは、本の勧める方法では、 funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別のソースファイルで定義されているという意味ではないか)ということです。 extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。 私の処理系では、 ・プロトタイプ宣言でexternを付けて関数定義でstaticを付ける、 ・staticを付けた関数を他のソースファイルで呼ぶ、 などの明らかに矛盾する場合は、コンパイルエラーになります。 でも、extern単独での役割はなさそうです。 他の処理系でも同じでしょうか。 (main等省略)

  • 外部ファイルでのtemplate関数の実装方法

    外部ファイルでのtemplate関数の実装方法 sub.cppにtemplate関数を実装し、 main.cppで、sub.cppのtemplate関数を呼び出す、 みたいなことをやりたいのですが、 コンパイルは通りますが、リンクエラー?になってしまいます。 以下が上記のサンプルプログラムです。 //main.cpp #include <vector> #include <iostream> using namespace std; template <typename t_ret, typename t_array> t_ret sub_t(const t_array&); int main (int argc, char *argv[]) { vector<double> v; v.push_back(1.1); v.push_back(2.2); cout << sub_t<double, vector<double> >(v) << endl; return 0; } // sub.cpp #include <vector> using namespace std; template <typename t_ret, typename t_array> t_ret sub_t(const t_array& array) { return array[0]+array[1]; } //コンパイルログ main.o: In function `main': main.cpp:(.text+0x134): undefined reference to `double sub_t<double, std::vector<double, std::allocator<double> > >(std::vector<double, std::allocator<double> > const&)' collect2: ld returned 1 exit status make: *** [main] Error 1 どなたか、対処方法を教えてください。 宜しくお願いします。

  • エラーが改善できません。

    C:\__Home\Visual Studio 2008\Projects\fecgsepfast>make MAKE Version 5.2 Copyright (c) 1987, 2000 Borland g++ -o fecgsep -O3 -lm ./src/fecgsep.cpp ./src/mem_util.cpp -L ./ -lica_ dll_amd ./src/fecgsep.cpp: In function 'int main(int, char**)': ./src/fecgsep.cpp:245:22: warning: name lookup of 'i' changed ./src/fecgsep.cpp:28:9: warning: matches this 'i' under ISO standard rules ./src/fecgsep.cpp:203:17: warning: matches this 'i' under old rules C:\DOCUME~1\Wada\LOCALS~1\Temp\cc6RcquX.o:fecgsep.cpp:(.text+0x41f): undefined r eference to `_imp___Z13fnica_dll_amdPdiiS_b' C:\DOCUME~1\Wada\LOCALS~1\Temp\cc6RcquX.o:fecgsep.cpp:(.text+0x718): undefined r eference to `_imp___Z13fnica_dll_amdPdiiS_b' collect2: ld returned 1 exit status ** error 1 ** deleting a.out というエラーが改善できません。どなたかアドバイスをお願いします。

  • linuxにおけるCの自作ヘッダファイル

    現在C言語のしっかりと学ばなかった部分を学習したいと思い、自作ヘッダファイルの作成を勉強しています。 そこで、書籍のその章を一通り読んだあと、自分で簡単なものを作成してみましたが、エラーが出てうまくいきません。 どうしてかわかる方いたら教えてください。 コード *****main.c***** #include "print.h" int main(void) { print(); return 0; } *****print.c***** #include <stdio.h> void print(void) { printf("test\n"); } *****print.h***** extern void print(void); エラー /tmp/ccH551c1.o: In function `main': /home/ユーザ名/Documents/StudyC/main.c:5: undefined reference to `print' collect2: ld returned 1 exit status CentOS6.6にて端末上での実行です。 自分の解釈では、""でincludeすることでカレントディレクトリから目的のヘッダファイルを見つけ出してインクルードする、また、ヘッダファイル内でexternすることによってprint.cから目的の関数を定義しているので、main.cでは問題なく使えると思っています。 しかし、エラーではprint()が定義されていないと出るのでまったくわかりません・・・。

  • gccでコンパイル時のエラー

    // test.cpp #include <stdio> using namespace std; int main(int argc, char *argv[]) { printf("test\n"); return 0; } 上記コードをコンパイルしたいのですが make -k g++ -g -O2 -Wall -I. -c test.cpp -o test.obj test.cpp:2:17: stdio: No such file or directory test.cpp: In function `int main(int, char**)': test.cpp:7: error: `printf' was not declared in this scope test.cpp:7: warning: unused variable 'printf' make: *** [test.obj] Error 1 make: Target `all' not remade because of errors. となります。 #include <stdio> using namespace std; を #include <stdio.h> // using namespace std; にすれば正常に終了するのですがなぜでしょうか? gccはMingw5.1.6からインストールしたもので、 バージョンはgcc3.4.5です。 Meadow上から実行しました。 回答よろしくお願い致します。