g++ 链接 变量被多次定义?

新手上路,请多包涵

这是map_test.h文件

#ifndef _MAP_TEST_H
#define _MAP_TEST_H

#include <map>
#include <string>

using std::map;
using std::string;

map<string, string> map_config;

void init_map_config();

#endif

这是map_test.cpp文件

#include "map_test.h"

void init_map_config()
{
    map_config.insert({"123", "123"});
    map_config.insert({"456", "456"});
    map_config.insert({"789", "789"});
}

这是main.cpp文件

#include <iostream>
#include "map_test.h"

using std::cout;
using std::endl;

int main()
{
    init_map_config();

    for (auto it = map_config.begin(); it != map_config.end(); it++)
        cout << it->first << " " << it->second << endl;
    cout << endl;
}

编译:
g++ -c map_test.cpp -o map.o -std=c++11
g++ -c main.cpp -o main.o -std=c++11
编译都是成功的,链接过程出错:
g++ map.o main.o -o main
此时出错:

main_test.o:(.bss+0x0): `map_config'被多次定义
map_test.o:(.bss+0x0):第一次在此定义
collect2: error: ld returned 1 exit status

为什么会报错?

阅读 8.3k
4 个回答

因为违背了ODR。map_config定义在头文件中,并且是外部链接。这个头文件分别被两个源文件包含,这导致链接时map_config在两个目标文件中有定义。

解决方案是将定义移到源文件中,在头文件中只留下纯声明。

1,在map_test.cpp文件中定义map<string, string> map_config;
2,在map_test.h中使用extern map<string, string> map_config;

变量和函数的定义 , 都应该放在cpp文件中, 否则很容易产生多重定义.
为什么呢?
因为c++的编译单位是cpp文件. 如果这个头文件被多个cpp包含了, 那么这个头文件中的定义的变量或者 函数就会在这些cpp生成的obj中存在, 在链接的时候, 就会发现多个obj存在同一个变量或者函数实现, 自然就会报重定义了.

所以:
除非你能清楚的知道, 这个头文件只会被一个cpp文件包含一次. 那么放到头文件中没有问题.
如果不确定, 那么变量定义或者函数的实现, 就老实的放到.cpp文件中吧.

可能你要问, 变量放到.cpp中的, 那么其它文件中如何使用它呢?
答案是使用声明: extern
比如: extern map<string, string> map_config;

新手上路,请多包涵

有两种解决办法

  1. 在头文件中使用extern声明,在源文件中定义

  2. 将map<string, string> map_config和函数init_map_config都定义为static

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题