C++ 프로젝트에서 소켓 통신을 구현하던 중, #include <WinSock2.h>와 #pragma comment(lib, "ws2_32.lib")를 모두 작성하게 되었다. 이 두 줄이 각각 어떤 역할을 하는지, 그리고 라이브러리 링킹 방식에 대해 정리해 보았다.
1. 두 줄을 모두 적어야 하는 이유
socket을 사용하기 위해 필요한 Windows 소켓 라이브러리(ws2_32.dll)가 외부 라이브러리이기 때문이다.
- #include <WinSock2.h>: 전처리기가 헤더 파일에서 함수의 프로토타입과 구조체 정의를 가져온다. 이를 통해 컴파일러는 socket() 같은 함수가 존재함을 인지하고 코드를 컴파일할 수 있게 된다.
- #pragma comment(lib, "ws2_32.lib"): 실제 함수의 구현체가 담긴 라이브러리 파일 ws2_32.lib를 링커에게 알려준다. 참고로, visual studio의 메뉴(프로젝트 속성 -> 링커 -> 입력 -> 추가 종속성에 ws2_32.lib 기입)에서 직접 추가하는 것도 동일한 효과를 낸다.
2. 정적 링킹(Static) vs 동적 링킹(Dynamic)
링킹은 오브젝트 파일들과 라이브러리를 하나로 묶어 하나의 실행 파일로 만드는 과정이다.
- 정적 링킹: 정적 라이브러리에서 필요한 코드를 찾아 실행 파일에 복사하는 방식이다. 실행 파일 크기는 커지고 라이브러리 수정 시 파일 전체를 다시 링킹해야 한다. 별도의 라이브러리 파일 없이 실행 파일만 있으면 프로그램 실행이 가능하다.
- 동적 링킹: 라이브러리 코드를 복사하지 않고, 해당 함수가 어디에 있는지에 대한 정보만 가진다. 실행 시(런타임) 메모리에 로드된 dll을 참조하여 필요한 내용을 가져온다.
3. 동적 링킹의 두 가지 방식: 암시적 vs 명시적
A. 암시적 링킹 (Implicit Linking)
프로그램 시작 시 OS가 필요한 dll을 자동으로 로드하는 방식이다. 가장 일반적으로 사용된다.
- 필요 요소: 헤더 파일(.h) + 임포트 라이브러리(.lib)
- 특징: .lib 파일에는 실제 코드가 아닌, dll 내 함수의 위치를 가리키는 심볼 정보가 들어있다. 링커는 이 정보를 바탕으로 실행 파일에 함수가 어떤 dll에 있는지를 기록한다.
- 장점: dll에 정의된 함수를 마치 자신의 함수처럼 호출할 수 있다. 호출 방식이 일반 함수와 같아 사용이 매우 쉽다.
- 단점: dll을 찾을 수 없으면 프로그램 자체가 실행되지 않는다.
B. 명시적 링킹 (Explicit Linking)
- 프로그램 실행 중에 코드에서 직접 dll 함수를 요청하는 방식이다.
- 필요 요소: dll 파일만 있으면 된다.
- 특징: LoadLibrary를 호출해 DLL을 메모리에 올린다. GetProcAddress로 함수의 주소(함수 포인터)를 얻어와 dll 함수를 호출한다. 사용이 끝나면 FreeLibrary로 메모리를 해제한다.
- 장점: 필요한 시점에만 로드하므로 메모리를 절약할 수 있고, dll이 없더라도 프로그램이 바로 종료되지 않고 예외 처리가 가능하다.
4. Deep Dive: DLL의 메모리 공유 방식
Q: 여러 프로세스가 동일한 DLL을 사용할 때, 메모리에는 어떤 식으로 올라갈까?
(1) 코드 영역(Code Segment)의 공유
DLL의 코드는 실행 파일에 포함되지 않고 별도로 존재한다.
OS는 여러 프로세스가 같은 DLL을 필요로 하면, 물리 메모리에 한 번 로드한다.
이후 각 프로세스의 가상 메모리가 물리 메모리에 있는 DLL 코드를 동시에 가리키게 만든다.
해당 가상 메모리의 주소 공간을 code segment(코드 영역)라 하며, 이로 인해 모든 프로세스에서 DLL 코드가 공유된다.
(2) 데이터 영역(Data Segment)의 독립성
이때, 각 프로세스가 사용하는 변수나 데이터는 프로세스마다 별도의 메모리 공간을 가진다.
이 부분을 data segment(데이터 영역)라 하는데, 이를 통해 각 프로세스가 서로의 데이터에 간섭하지 않고 독립적으로 동작할 수 있다.
운영체제(OS)의 가상 메모리 매핑에 따라 프로세스의 메모리는 여러 세그먼트로 나뉘는데, DLL 코드는 그 중 code segment(코드 영역)에 저장된다.
(3) DLL의 메모리 공유를 통한 이점
실행 파일마다 dll 코드를 포함하지 않으므로, 디스크 공간을 절약할 수 있다.
여러 프로그램이 같은 DLL 함수를 써도 메모리에는 실제 구현 코드가 하나만 올라가 있으므로, 메모리를 절약할 수 있다.
다른 프로그램에 의해 DLL이 메모리에 올라와 있다면, 연결만 하면 되므로 실행 속도가 빨라진다.
5. 참고자료
- https://stackoverflow.com/questions/6837036/why-do-some-header-files-require-libraries-to-be-linked-in-visual-studio
https://bradbury.tistory.com/224
https://bradbury.tistory.com/226
https://learn.microsoft.com/ko-kr/cpp/build/linking-an-executable-to-a-dll?view=msvc-170 - https://www.ibm.com/docs/ko/aix/7.2.0?topic=concepts-shared-libraries-shared-memory
'컴퓨터' 카테고리의 다른 글
| '클로드 코드 제대로 쓰는 법 | 5가지 필수 설정' 정리 (0) | 2026.08.16 |
|---|---|
| Claude Code 기반 백엔드 개발: 포트폴리오 자동화 (0) | 2026.08.16 |
| Blocking socket VS Non-blocking socket 및 버퍼 동작 원리 (0) | 2026.01.16 |
| [프로젝트] 투표 시스템 확장 (0) | 2026.01.15 |
| 윈도우에서 nginx와 php, mysql을 연동해보자 (0) | 2023.05.07 |