전역 및 정적 변수가있는 모듈이 응용 프로그램에 동적으로 연결될 때 어떤 일이 발생하는지 이해하려고합니다. 모듈이란 솔루션의 각 프로젝트를 의미합니다 (저는 Visual Studio에서 많이 작업합니다!). 이러한 모듈은 * .lib 또는 * .dll 또는 * .exe 자체에 내장되어 있습니다.
나는 응용 프로그램의 바이너리가 데이터 세그먼트에있는 모든 개별 번역 단위 (객체 파일)의 전역 및 정적 데이터를 포함하고 있음을 이해합니다 (그리고 const 인 경우 데이터 세그먼트 만 읽음).
-
이 응용 프로그램이로드 시간 동적 링크와 함께 모듈 A를 사용하면 어떻게됩니까? DLL에 전역 및 통계에 대한 섹션이 있다고 가정합니다. 운영 체제에서로드합니까? 그렇다면 어디로로드됩니까?
-
그리고 응용 프로그램이 런타임 동적 연결이있는 모듈 B를 사용하면 어떻게됩니까?
-
응용 프로그램에 A와 B를 모두 사용하는 두 개의 모듈이있는 경우 A와 B의 전역 복사본이 아래와 같이 생성됩니까 (다른 프로세스 인 경우)?
-
DLL A와 B가 응용 프로그램 전역에 액세스 할 수 있습니까?
(이유도 기재 해주세요)
MSDN 에서 인용 :
DLL 소스 코드 파일에서 전역으로 선언 된 변수는 컴파일러와 링커에서 전역 변수로 처리되지만 지정된 DLL을로드하는 각 프로세스는 해당 DLL 전역 변수의 자체 복사본을 가져옵니다. 정적 변수의 범위는 정적 변수가 선언 된 블록으로 제한됩니다. 결과적으로 각 프로세스에는 기본적으로 DLL 전역 및 정적 변수의 자체 인스턴스가 있습니다.
그리고 여기에서 :
모듈을 동적으로 연결할 때 서로 다른 라이브러리에 자체 전역 인스턴스가 있는지 또는 전역이 공유되는지 여부가 명확하지 않을 수 있습니다.
감사.
답변
이것은 Windows와 Unix 계열 시스템 간의 매우 유명한 차이점입니다.
무슨 일이 있어도:
- 각 프로세스 에는 고유 한 주소 공간이 있습니다. 즉, 프로세스 간 통신 라이브러리 또는 확장을 사용하지 않는 한 프로세스간에 공유되는 메모리가 없습니다.
- 하나의 정의 규칙 (ODR)는 여전히 만 링크시 (정적 또는 동적 링크)에서 볼 수 전역 변수 중 하나 정의를 가질 수 있다는 것을 의미 적용됩니다.
따라서 여기서 핵심 문제는 가시성입니다. 입니다.
모든 경우에, static
전역 변수 (또는 함수)는 모듈 (dll / so 또는 실행 파일) 외부에서 볼 수 없습니다. C ++ 표준에서는 이러한 파일에 내부 연결이 있어야합니다. 즉, 정의 된 변환 단위 (개체 파일이 됨) 외부에서는 볼 수 없습니다. 그래서 그 문제가 해결됩니다.
복잡 해지는 곳은 extern
전역 변수 가있을 때 입니다. 여기서 Windows와 Unix 계열 시스템은 완전히 다릅니다.
Windows (.exe 및 .dll)의 경우 extern
전역 변수는 내 보낸 기호의 일부가 아닙니다. 즉, 다른 모듈은 다른 모듈에 정의 된 전역 변수를 인식하지 못합니다. 예를 들어 extern
DLL에 정의 된 변수 를 사용하는 실행 파일을 만들려고하면 링커 오류가 발생합니다 . 이는 허용되지 않기 때문입니다. 해당 extern 변수의 정의와 함께 개체 파일 (또는 정적 라이브러리)을 제공하고이를 실행 파일과 DLL 모두에 정적으로 연결 하여 두 개의 개별 전역 변수 (하나는 실행 파일에 속하고 다른 하나는 DLL에 속함)를 생성해야합니다. ).
Windows에서 실제로 전역 변수를 내보내려면 함수 내보내기 / 가져 오기 구문과 유사한 구문을 사용해야합니다.
#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif
MY_DLL_EXPORT int my_global;
그렇게하면 전역 변수가 내 보낸 심볼 목록에 추가되고 다른 모든 기능과 마찬가지로 링크 될 수 있습니다.
Unix와 유사한 환경 (Linux와 같은)의 경우 확장이있는 “공유 객체”라고하는 동적 라이브러리는 .so
모든 extern
전역 변수 (또는 함수)를 내 보냅니다 . 이 경우 어디에서나 공유 객체 파일로 로드 타임 링크 를 수행 하면 전역 변수가 공유됩니다. 즉, 하나로 함께 링크됩니다. 기본적으로 유닉스 계열 시스템은 정적 라이브러리와 동적 라이브러리와의 링크 사이에 사실상 차이가 없도록 설계되었습니다. 다시 말하지만, ODR은 보드 전체에 적용됩니다. extern
전역 변수는 모듈간에 공유됩니다. 즉,로드 된 모든 모듈에 대해 하나의 정의 만 있어야합니다.
마지막으로 두 경우 모두 Windows 또는 Unix 계열 시스템의 경우 / / 또는 / / 중 하나를 사용하여 동적 라이브러리의 런타임 링크를 수행 할 수 있습니다 . 이 경우 사용하려는 각 기호에 대한 포인터를 수동으로 가져와야하며 여기에는 사용하려는 전역 변수가 포함됩니다. 전역 변수의 경우 전역 변수가 내 보낸 기호 목록의 일부인 경우 (이전 단락의 규칙에 따라) 함수에 대해 수행하는 것과 동일 하거나 사용할 수 있습니다 .LoadLibrary()
GetProcAddress()
FreeLibrary()
dlopen()
dlsym()
dlclose()
GetProcAddress()
dlsym()
그리고 물론 필요한 마지막 참고 사항으로 전역 변수는 피해야 합니다. 그리고 당신이 인용 한 텍스트 ( “불분명 한 것”에 대해)는 방금 설명한 플랫폼 별 차이점을 정확히 언급한다고 믿습니다 (동적 라이브러리는 실제로 C ++ 표준에 의해 정의되지 않습니다. 이것은 플랫폼 별 영역입니다. 훨씬 덜 신뢰성 / 휴대 성).