C++编译遇到重复定义问题

一直对编译这个事情不是太明白,想好好学习一下,今天自己写东西试验,遇到了这么个问题,想请教一下,先贴代码

// test.h
#ifndef JUST_FOR_TEST_H_
#define JUST_FOR_TEST_H_

struct Test {
  static int i;
  void t();
};

int Test::i = 0;

#endif
// test.cpp 
#include "test.h"

void Test::t() { }
// main.cpp
#include "test.h"

int main() {
  Test t;
  t.t();
}

本来觉得这个是很简单的,但是链接的时候报了错,提示是

ld: 1 duplicate symbol for architecture x86_64

将test.h中静态成员的定义放到cpp文件中就好了,但是我很不理解,不是使用了头文件保护吗?这样不是已经确保了一个头文件在一个工程中只会被包含一次吗?是我哪里的理解出了偏差了吗?希望各位高手可以指点一下,本人菜鸡,不是学计算机出身的,所以问的问题可能很傻,如果可以的话希望可以讲的详细一点,如果可以介绍两本学习的书就更好了,先谢过了!

 

 

你遇到的链接错误实际上是由于违背ODR引起的。

ODR约定:

Only one definition of any variable, function, class type, enumeration type, or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed).

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries).

但除此之外还有很多的特例。在这里就不列举了(主要因为是我列不全……)。

其中有三个概念很重要:translation unit, definition和program.

translation unit是编译单元,一共有几个编译单元由编译指令决定。编译单元的编译结果称为目标文件。definition是定义,在这个例子中int Test::i = 0;是静态成员变量i的定义,根据ODR,这个定义在整个程序中只能出现一次。program是程序,程序由众多的目标文件链接而成。

编译指令:clang++ main.cpp test.cpp -o main

此次编译一共有两个编译单元main.cpp和test.cpp。他们会被分别编译成目标文件。#include是预编译宏,他会引入对应文件的内容,并且所有的预编译指令都会在源代码被编译前执行。也就是说编译单元"test.cpp"的内容(或者说clang编译器收到的代码)为:

// test.cpp
// test.h
struct Test {
  static int i;
  void t();
};

int Test::i = 0;

void Test::t() { }

编译单元"main.cpp"的内容为:

// main.cpp
// test.h
struct Test {
  static int i;
  void t();
};

int Test::i = 0;

int main() {
  Test t;
  t.t();
}

所有的宏都执行完毕,注释会被编译器忽略。

这两个编译单元会被分别编译成目标文件,比方说test.o和main.o。编译工作结束。然后编译器会将这两个目标文件test.o和main.o链接成一个程序,违背ODR就是在这个链接时发生的

如果int Test::i = 0;的定义在test.cpp中。那么在main.cpp中就不会出现这个定义,也就没有违背ODR。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值