为什么c ++将在单独模块中定义的同名变量放入内存中的相同地址?

Nic*_*ick 3 c++ g++

我们来看头文件 var.h

#include <iostream>

class var
  {public:
      var () {std::cout << "Creating var at " << this << std::endl; }
      ~var () {std::cout << "Deleting var at " << this << std::endl; }
  };
Run Code Online (Sandbox Code Playgroud)

和两个源文件,第一个 lib.cpp

#include "var.h"
var A;
Run Code Online (Sandbox Code Playgroud)

第二个 app.cpp

#include "var.h"

var A;

int main ()
  {return 0;
  }
Run Code Online (Sandbox Code Playgroud)

那么,如果我试图编译它们

g++ -c app.cpp
g++ -c lib.cpp
g++ -o app app.o lib.o
Run Code Online (Sandbox Code Playgroud)

链接器返回多个定义的变量错误.但是,如果我将它编译到共享库+主应用程序

g++ -fPIC -c lib.cpp
g++ --shared -o liblib.so lib.o
g++ -fPIC -c app.cpp
g++ -o app -llib -L . app.o
Run Code Online (Sandbox Code Playgroud)

它没有错误地链接.但是程序无法正常工作:

./app
Creating var at 0x6013c0
Creating var at 0x6013c0
Deleting var at 0x6013c0
Deleting var at 0x6013c0
Run Code Online (Sandbox Code Playgroud)

所以在同一个内存地址创建了不同的变量!例如,在库和应用程序期望它们具有不同的值(在这种情况下为对象字段的值)的情况下,它可能会遇到严重的麻烦.

如果class var内存分配/删除valgrind警告访问最近删除的块中的内存.

是的,我知道我可以static var A;代替var A;并且两种编译方式都能正常工作.我的问题是:为什么不能在不同的库中使用同名变量(甚至函数?)?图书馆创建者可能对彼此使用的名称一无所知,也不会被警告使用static.为什么GNU链接不会警告这种冲突?

而且,BTW,可能会dlload遇到同样的麻烦?

UPD.谢谢大家解释有关命名空间和extern的问题,我看到为什么相同的符号被放入相同的内存地址,但我仍然无法理解为什么没有显示链接错误甚至是关于双重定义变量的警告,而是在第二种情况下生成了错误的代码.

小智 5

我的问题是:为什么不能在不同的库中使用同名变量(甚至函数?)?

您可以.你遗漏的是声明

var A;

没有定义A在库中使用的符号.他们定义了要导出的符号,以便任何其他编译单元可以引用它!

例如,如果,在app.cpp,你宣布

extern var A;

这意味着申报" A是类型的变量var,其他一些编译单元是要界定和出口" -这个修改您的设置,这将使app.cpp明确要求使用指定的对象Alib.cpp出口.

您的设置问题是您有两个不同的编译单元都试图导出相同的符号A,这会导致冲突.

Why GNU linked doesn't warn about this conflict?

因为GNU不知道你想A成为编译单元的私有变量,除非你告诉 GNU它应该是你的编译单元私有的.这就是这方面的static意思.