gpt4 book ai didi

c++ - 当使用静态成员将共享库静态链接到可执行文件时,我在 UNIX 和 WIN 上收到不同的结果。请解释为什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:44:01 27 4
gpt4 key购买 nike

请考虑以下代码和平:

// 1. Single header file. Imagine that it is some static library.
// Counter.h
#pragma once

struct Counter
{
Counter()
{
++getCount();
}

static int& getCount()
{
static int counter = 0;
return counter;
}
};

// 2. Shared library (!) :
// main_DLL.cpp
#include <iostream>
#include "counter.h"

extern "C"
{
__declspec(dllexport) // for WIN
void main_DLL()
{
Counter c;
std::cout << "main_DLL : ptr = " << &Counter::getCount()<< " value = " << Counter::getCount() << std::endl;
}
}

// 3. Executable. Shared library statically (!) linked to the executable file.
// main.cpp

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

extern "C"
{
__declspec(dllimport) // for WIN
void main_DLL();
}

int main()
{
main_DLL();
Counter c;
std::cout << "main_EXE : ptr = " << &Counter::getCount() << " value = " << Counter::getCount() << std::endl;
}

结果:

Results for WIN (Win8.1 gcc 5.1.0):
main_DLL : ptr = 0x68783030 value = 1
main_EXE : ptr = 0x403080 value = 1
// conclusion: two different counters

Results for UNIX (Red Hat <I don’t remember version exactly> gcc 4.8.3):
main_DLL : ptr = 0x75693214 value = 1
main_EXE : ptr = 0x75693214 value = 2
// conclusion: the same counter addressed

建筑:

Building for WIN:
g++ -c -Wall -Werror -o main_DLL.o main_DLL.cpp
g++ -shared -Wl,--out-implib=libsharedLib.a -o libsharedLib.so main_DLL.o
g++ -Wall –Werror -o simpleExample main.cpp -L./ -lsharedLib

Building for UNIX:
g++ -c -Wall -Werror -fPIC -o main_DLL.o main_DLL.cpp
g++ -shared -fPIC -o libsharedLib.so main_DLL.o
g++ -Wall –Werror -fPIC -o simpleExample main.cpp -L./ -lsharedLib

因此,您看到我在 UNIX 上添加了 –fPIC 并且不需要为 UNIX 创建导入库,因为所有导出符号都包含在共享库中。在 Windows 上,我为此使用 __declspec。

对我来说,Windows 上的结果非常令人期待。因为共享库和可执行文件是分开构建的,所以它们应该知道 Counter::getCount 中的静态变量。他们应该简单地为其分配内存,这就是为什么他们有不同的静态计数器。

我使用 nm、objdump 等工具进行了相当多的分析。虽然我不是他们的大专家,所以我没有发现任何可疑之处。如果需要,我可以提供他们的输出。

使用 ldd 工具我可以看到在这两种情况下静态链接的库。

为什么我在 Unix 上看不到相同的结果,这很奇怪。根本原因可能在于构建选项(例如 –fPIC),还是我遗漏了什么?

最佳答案

在 Windows 中,除非您添加 dllexport 语句,否则 DLL 不会导出全局和静态符号,因此,链接器甚至不知道它们的存在,因此它会为静态成员分配新的实例.

在 linux/unix 中,共享库导出所有全局和静态符号,因此当链接器发现共享库中存在静态成员时,它只使用其地址。

这就是不同结果的原因。

关于c++ - 当使用静态成员将共享库静态链接到可执行文件时,我在 UNIX 和 WIN 上收到不同的结果。请解释为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31495877/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com