エラー一覧を見ると、行番号が書いてありません。代わりに書いてあるのは、a.objとmain.objという、ソースコードではないファイル名です。「既に定義されています」と言われても、どこを開けばいいのか分からない。LNK2005は、そういう迷子になりやすいエラーです。
先に答えを言うと、犯人はたいてい、ヘッダーファイルに書いた「実体」です。同じヘッダーを2つのcppが読むと、実体が2つできてしまいます。この記事では、これを実際に起こして、直し方を比べました。直し方によっては、エラーは消えるのに、値が別々になるものもあります。
検証は、Visual Studio 2022付属のMSVC(19.44、x64)を、コマンドラインのclで動かして行いました。前に書いたLNK2019(未解決の外部シンボル)が「実体が足りない」エラーなのに対して、今回のLNK2005は「実体が多すぎる」エラーです。
LNK2005とは?
LNK2005とは、
・リンクのとき、同じ名前の関数や変数の実体が、2か所以上で見つかったときに出るエラー
です。必ずLNK1169(複数回定義されているシンボルが見つかりました)とセットで出ます。
ポイントは、C++のビルドが、cppファイルを1つずつ別々にコンパイルすることです。ヘッダーに実体を書くと、そのヘッダーを#includeしたcppの数だけ、同じ実体がコピーされます。リンカーは、それらを1つにまとめられないので、エラーにします。#pragma onceやインクルードガードは、1つのcppの中での二重読み込みしか防げません。cppどうしの重複は、防げないのです。
原因を6パターン再現する
①ヘッダーに、関数の実体を書いた
いちばん多い原因です。ヘッダー(util.h)に、関数の中身まで書いてしまいました。
▼util.h
#pragma once
int add(int a, int b)
{
return a + b;
}▼a.cpp
#include "util.h"
int fromA()
{
return add(1, 2);
}▼main.cpp
#include <cstdio>
#include "util.h"
int fromA();
int main()
{
std::printf("fromA = %d, add = %d\n", fromA(), add(3, 4));
return 0;
}main.cpp
a.cpp
コードを生成中...
a.obj : error LNK2005: "int __cdecl add(int,int)" (?add@@YAHHH@Z) は既に main.obj で定義されています。
main.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。main.cppもa.cppもutil.hを読むので、addの実体が、main.objとa.objの両方にできました。エラー文の「既にmain.objで定義されています」は、「a.objのaddが、main.objにあるものと重なった」という意味です。2つのobjに共通するヘッダーを探せば、犯人が見つかります。
直すには、関数にinlineを付けます。inlineは、「同じ実体が複数のcppにあっても、1つにまとめてよい」という印です。
▼util.h(直した)
#pragma once
inline int add(int a, int b)
{
return a + b;
}fromA = 3, add = 7②ヘッダーに、変数の実体を書いた
グローバル変数でも、同じことが起きます。
▼var.h
#pragma once
int g_count = 0;▼a.cpp
#include "var.h"
void countUp()
{
++g_count;
}
int readA()
{
return g_count;
}▼main.cpp
#include <cstdio>
#include "var.h"
void countUp();
int readA();
int main()
{
countUp();
countUp();
countUp();
std::printf("main側 g_count = %d / a.cpp側 g_count = %d\n", g_count, readA());
return 0;
}main.cpp
a.cpp
コードを生成中...
a.obj : error LNK2005: "int g_count" (?g_count@@3HA) は既に main.obj で定義されています。
main.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。こちらも、同じ形のエラーになりました。変数の直し方は3通りあります。それぞれ実行して、g_countを3回増やしたあとの値を比べました。
【重要】staticで直すと、エラーは消えるが、値が別物になる
エラーが消えるから、とstaticを付ける直し方を、よく見かけます。
▼var.h(staticを付けた)
#pragma once
static int g_count = 0; // それぞれのcppに、別々の変数ができるmain側 g_count = 0 / a.cpp側 g_count = 3ビルドは通りましたが、実行結果が変です。a.cppの中で3回増やしたのに、main.cppから見ると、g_countは0のままでした。staticを付けると、変数が、cppファイルごとに別々に作られるからです。「共有したい変数」にstaticを付けると、エラーは消えても、コードの意味が変わります。
共有したいなら、次の2つの方法を使います。
▼var.h(宣言だけにした)
#pragma once
extern int g_count; // 宣言だけ(実体はglobals.cppに1つだけ)▼globals.cpp(実体は、ここだけ)
#include "var.h"
int g_count = 0; // 実体はここだけmain側 g_count = 3 / a.cpp側 g_count = 3externは、「実体は、どこか別の場所にあります」という宣言です。実体を、1つのcppだけに書いて、ヘッダーには宣言だけを置くと、両方から同じ変数が見えて、3と3になりました。
C++17以降なら、もっと簡単な方法があります。inlineを、変数にも付けられるようになりました。
▼var.h(inline変数)
#pragma once
inline int g_count = 0; // C++17: ヘッダーに書いても、実体は1つにまとめられるmain側 g_count = 3 / a.cpp側 g_count = 3実体を書くファイルを増やさずに、3と3で共有できました。ただし、C++14以前では使えません。同じコードを/std:c++14でビルドすると、次のエラーになりました。
main.cpp
C:\blogtest\dup\c2_inline\var.h(3): error C7525: インライン変数には、最低でも '/std:c++17' が必要です
a.cpp
C:\blogtest\dup\c2_inline\var.h(3): error C7525: インライン変数には、最低でも '/std:c++17' が必要です
コードを生成中...③クラスのメンバ関数を、ヘッダーのクラスの外に書いた
クラスの宣言は.h、メンバ関数の中身は.cpp、というルールを守ったつもりで、ヘッダーの中で、クラスの外に中身を書いてしまうパターンです。
▼player.h
#pragma once
class Player
{
public:
int hp() const;
};
int Player::hp() const
{
return 100;
}main.cpp
a.cpp
コードを生成中...
a.obj : error LNK2005: "public: int __cdecl Player::hp(void)const " (?hp@Player@@QEBAHXZ) は既に main.obj で定義されています。
main.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。メンバ関数Player::hpが、重複しました。直し方は2通りで、どちらも実行できました。
▼player.h(クラスの中に書く)
#pragma once
class Player
{
public:
int hp() const { return 100; } // クラスの中に書くと、自動でinline扱いになる
};fromA = 100, main = 100▼player.h(クラスの外に書く場合は、inlineを付ける)
#pragma once
class Player
{
public:
int hp() const;
};
inline int Player::hp() const // クラスの外に書くなら、inlineを付ける
{
return 100;
}fromA = 100, main = 100クラスの中に書いた関数は、自動でinline扱いになるので、何も付けなくてよいのです。
④cppファイルを、#includeしている
ヘッダーではなく、cppファイル自体を#includeしてしまうパターンです。cppを読み込むと、その中身が、そっくりコピーされます。
▼main.cpp
#include <cstdio>
#include "a.cpp" // .cppをincludeしている
int main()
{
std::printf("fromA = %d\n", fromA());
return 0;
}main.cpp
a.cpp
コードを生成中...
a.obj : error LNK2005: "int __cdecl fromA(void)" (?fromA@@YAHXZ) は既に main.obj で定義されています。
main.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。a.cppは、単独でもビルドされるので、fromAが2つできました。直すには、宣言だけの.hを作って、そちらを#includeします。
▼a.h
#pragma once
int fromA();fromA = 42⑤ランタイムライブラリの設定が、ライブラリと食い違っている
自分のコードに重複が無くても、LNK2005が出ることがあります。標準ライブラリ(CRT)の種類が、exeとlibで食い違っているときです。ランタイムライブラリには、/MT(静的リンク)と/MD(DLLを使う)があります。/MTで作ったlibを、/MDのexeからリンクしてみました。ライブラリ側はiostreamとstringを使っています。
▼crtlib.cpp(/MTでlibにした)
#include <iostream>
#include <string>
void hello()
{
std::string s = "hello from lib";
std::cout << s << std::endl;
}▼main.cpp(/MDでビルド)
#include <iostream>
void hello();
int main()
{
hello();
std::cout << "main" << std::endl;
return 0;
}main.cpp
crtlib.lib(crtlib.obj) : error LNK2038: 'RuntimeLibrary' の不一致が検出されました。値 'MT_StaticRelease' が MD_DynamicRelease の値 'main.obj' と一致しません。
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: bool __cdecl std::ios_base::good(void)const " (?good@ios_base@std@@QEBA_NXZ) は既に crtlib.lib(crtlib.obj) で定義されています。
(中略: 同じ形のエラーが、ほかに51行続く)
LINK : warning LNK4098: defaultlib 'LIBCMT' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
main.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。LNK2005が24行、LNK2038(RuntimeLibraryの不一致が検出されました)が29行、合計50行以上のエラーが出ました。最初に出ているLNK2038の文面が、本当の原因を教えてくれています。「MT_StaticReleaseとMD_DynamicReleaseが一致しません」。直すには、libも/MDで作り直して、設定をそろえます。
hello from lib
mainVisual Studioでは、プロジェクトのプロパティの「C/C++ → コード生成 → ランタイムライブラリ」が、この設定です。exe側と、リンクするlib側で、同じ種類にそろえます。
なお、同じ/MTと/MDの食い違いでも、printfしか使わないlibでは、別の結果になりました。
main.cpp
LINK : warning LNK4098: defaultlib 'LIBCMT' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。今回の環境では、LNK4098の警告が出ただけで、リンクは通り、実行も成功しました(hello from libとmainが表示されました)。エラーにならないから安全、とは限らないので、警告が出たら、設定をそろえておくのが無難です。
⑥const変数は、重複しない
最後に、「ヘッダーに変数を書くと、必ず重複する」わけではない、という例です。constを付けたグローバル変数は、C++では、ファイルごとに独立した変数として扱われます(内部リンケージ)。
▼consts.h
#pragma once
const int kMax = 10; // constのグローバル変数は、ファイルごとに内部リンケージfromA = 20, kMax = 10エラーは出ず、問題なく動きました。定数をヘッダーに書くときは、const(またはconstexpr)を付けておけば、重複の心配はありません。
原因ごとの、直し方の早見表
| 書いてあったもの | エラー文の特徴 | 直し方 |
|---|---|---|
| ヘッダーの関数の実体 | int __cdecl add(int,int)のように、関数名が出る | inlineを付ける、またはcppに移す |
| ヘッダーの変数の実体 | int g_countのように、変数名が出る | extern+cppに実体、またはC++17のinline変数 |
| クラス外のメンバ関数の実体 | public: int __cdecl Player::hp(void)const | クラスの中に書く、またはinlineを付ける |
#include "a.cpp" | a.cppにある関数が、重複している | 宣言だけの.hを作って、そちらを読む |
/MTと/MDの混在 | LNK2038やmsvcprt.libが大量に出る | exeとlibで、ランタイムライブラリをそろえる |
LNK2005のよくある失敗例と対処法
①インクルードガードがあるのに、なぜ?と悩む
#pragma onceは、1つのcppの中で、同じヘッダーを二重に読み込まないための仕組みです。cppは別々にコンパイルされるので、cppどうしの重複は防げません。
②staticを付けて、エラーを黙らせる
実験で見たとおり、共有したい変数にstaticを付けると、値が別々になります。エラーが消えたときは、「共有できているか」を、必ず確認します。
③エラー文の.objの名前から、犯人を探す
「a.objがmain.objと重なった」というエラー文は、両方のcppが、共通のヘッダーを読んでいることを示しています。2つのcppに共通する#includeから、探します。
注意点
- LNK2005は、同じ実体が、2か所以上にあるときのエラー。LNK2019(実体が無い)の、逆の状態
- インクルードガード(
#pragma once)は、cppどうしの重複は防げない - ヘッダーには、原則として宣言だけを書く。実体を書くなら
inline(C++17なら、変数にもinline) staticで直すと、値が別物になる(今回の実験では、3ではなく0が見えた)constのグローバル変数は、ファイルごとに別のものとして扱われるので、重複しない- 大量のLNK2005は、ランタイムライブラリの不一致(
LNK2038)が原因のことがある - 今回は、MSVC 19.44(Visual Studio 2022付属、
/std:c++17)で確認した。エラー文の細部は、版で変わりうる
この記事の要点
- LNK2005は、ヘッダーに実体を書いたことが、いちばん多い原因。エラー文の
.objは、「共通のヘッダーを探せ」というヒント - 直し方は、関数なら
inline、変数ならextern+1か所の実体か、C++17のinline変数 staticは、エラーを消すが、値を別物にする- 大量に出るときは、
LNK2038の文面(/MTと/MDの不一致)を、先に読む
ヘッダーには宣言、cppには実体。この分担を守るだけで、LNK2005の大半は避けられます。そして、もし出てしまったときは、エラー文の.objの名前を2つ並べて、「両方が読んでいるヘッダーはどれか」と考えれば、探す範囲がぐっと狭まります。


