[英]Why linker does not complain about multiple definitions when linking against shared and static
我最近在我正在開發的代碼中遇到了 static 初始化失敗的問題。 這讓我意識到我缺乏關於鏈接過程和全局變量初始化的知識,所以我在 cppcon 上發現了這個非常有趣的關於全局變量、鏈接以及將 static 庫嵌入共享和同時鏈接的可能問題(與全局變量定義)。 基本上說的是,當具有以下結構時:
//static.hpp
#pragma once
#include <string>
extern std::string globalString;
//static.cpp
#include "static.hpp"
std::string globalString;
//shared.hpp
#pragma once
#include "static.hpp"
#include <string>
std::string& getGlobalString();
//shared.cpp
#include "shared.hpp"
#include "static.hpp"
std::string& getGlobalString(){
return globalString;
}
//main.cpp
#include "static.hpp"
#include "shared.hpp"
#include <iostream>
int main(){
std::cout << "Global variable: " << globalString << std::endl;
std::cout << "Global var acccesed through shared lib: " << getGlobalString() << std::endl;
return 0;
}
所有編譯:
clang++ -c -std=c++14 -fpic static.cpp
clang++ -c -std=c++14 -fpic shared.cpp
clang++ -c -std=c++14 main.cpp
ar rsc libstatic.a static.o
clang++ -shared -o libshared.so shared.o -L./ -lstatic
clang++ -L./ -Wl,-rpath=./ main.o -lstatic -lshared
由於多次調用同一個 object 的構造函數和析構函數,導致分段錯誤。 這是令人驚訝的,因為我認為每個 object 構造函數都將被調用一次是不變的!
這是令人驚訝的,因為我認為每個 object 構造函數都將被調用一次是不變的!
在正確構造的二進制文件中,這是正確的。 在具有 ODR 違規的二進制文件中不一定正確。
關於多次調用構造函數/析構函數的標准是什么?
該標准規定,在正確構造的程序中,構造函數/析構函數只被調用一次。 在違反 ODR 的程序中,任何事情都可能發生(未定義的行為)。
如果在這種情況下,我將 static 的全局嵌入到 main.o 和 libshared.so 中,這是否意味着有一個定義的規則被打破了?
是的。
為什么 linker 在鏈接 main 時沒有抱怨第二個定義可用?
就 linker 而言,你的程序沒有問題。 從 linker 的角度來看,在 static 和共享庫中定義一個全局是完美的。 另請參閱此答案。
當在單獨的翻譯單元中至少有兩個全局時,建立構造和銷毀順序的建議方法之一是在第一次使用時進行初始化。 然而,據我所知,這只能確保施工順序。
正確的。 這是針對不同問題的解決方案:兩個全局變量 A 和 B 在單獨的翻譯單元中定義。
你沒有那個問題,你有一個完全不同的問題(違反 ODR)。
毀滅令呢? 如何控制?
在正確構造的程序中,破壞順序保證與構造順序相反。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.