* 분할 컴파일
여러 개의 소스 코드들을 따로 컴파일하는 작업
- #include "헤더"
여러 cpp 파일에서 같은 클래스/ 구조체를 사용하고 싶을 때
.h 파일을 include 하여 같은 내용을 여러번 작성할 필요가 없습니다.
.h 파일에 들어갈 수 있는 내용
1. 함수 원형
2. #define 혹은 const 변수
3. 구조체/ 클래스의 선언
4. 템플릿 선언
5. inline 함수
- 분할 컴파일의 장점
1. 파일의 분리로 인해 모듈화가 가능합니다.
2. 프로그램 수정 시 수정된 파일만 컴파일하여 컴파일 속도를 높입니다.
3. 모듈별 테스트 및 디버깅이 가능합니다.
* 기억 존속 시간
- C++은 네가지 유형으로 메모리를 저장합니다.
1. 자동 기억 존속 : 함수 또는 블럭 내부의 메모리가 해당 함수나 블록이 끝나면 해제됩니다.
2. 정적 기억 존속 : 전역/ static 변수를 의미하며, 프로그램이 끝나면 해제됩니다.
3. 쓰레드 존속 : 멀티코어 CPU에서 사용되는 것으로, 쓰레드 단위로 처리됩니다.
4. 동적 기억 존속 : new를 통해 기억되고, delete를 통해 해제되는 동적 변수입니다.
* 범위(Scope)
1. 외부 링크 : 여러 파일에서 공유 가능한 이름
2. 내부 링크 : 한 파일에서 공유 가능한 이름
3. 링크 없음 : 링크가 없습니다.
예시:
int global = 5; //외부링크
static int internal = 4; // 내부링크
int func()
{
static int count = 1; //링크 없음
return 0;
}
static 변수는 선언 시, 초기화해주지 않으면 모두 제로-초기화 됩니다. 이는 모든 비트가 0으로 설정됨을 의미합니다.
* 초기화
1. 제로초기화 : int A;
2. 상수 표시 초기화 : int B = 5;
3. 동적 초기화 : int C = sizeof(int) + 5;
* Extern
- 한 파일에서 extern int A; 와 같이 선언했다면, 외부 파일에서 해당 변수를 초기화해줄 수 있습니다.
- static이 없는 단순 전역 변수는 두 파일에서 링크될 경우 에러를 일으킬 수 있습니다.
예시:
//file1
int a = 5;
/*=========================================*/
//file2
int a = 10;
int main()
{
printf("%d", a);
return 0;
}
외부/내부 파일 링크에 따라 극단적으로 값이 달라지는 경우는 다음 예시와 같습니다.
//File1.cpp
#include <iostream>
int A = 3;
int B = 6;
static int C = 9;
void function();
int main()
{
printf("%d, %d, %d\n", A, B, C); //3, 6, 9
function();
}
//File2.cpp
#include <iostream>
extern int A;
static int B = 60;
int C = 90;
void function()
{
printf("func : %d, %d, %d\n", A, B, C); //func : 3, 60, 90
}
두 파일의 출력 결과가 extern과 static 키워드가 각각 어떻게 작동하는지 알려주는 단적인 예시입니다.
* CV-제한자
1. const : 생략합니다.
2. volatile : 컴파일러가 항상 메모리에 접근하도록 일러주는 제한자입니다.
- 요즈음 컴파일러는 매우 똑똑하기 때문에,
우리가 의도한 대로 프로그램을 동작시키지 않고 최적화시키는 경우가 있습니다.
C 언어 코딩 도장: 85.15 volatile 변수 (dojang.io)
C 언어 코딩 도장: 85.15 volatile 변수
변수를 선언할 때 앞에 volatile을 붙이면 컴파일러는 해당 변수를 최적화에서 제외하여 항상 메모리에 접근하도록 만듭니다. volatile 자료형 변수이름; volatile int num1 = 10; // 변수를 최적화에서 제
dojang.io
- 위 블로그에서 잘 알려주고 있듯이, volatile 키워드는 컴파일러의 최적화를 막습니다.
3. mutable
- 구조체 혹은 클래스가 const로 선언되어있다고 해도, 해당 내용을 변경할 수 있도록 조치합니다.
예시 :
struct T
{
int A;
mutable int C;
};
int main()
{
const T st = {3, 6};
st.C = 7; //가능
return 0;
}
* 맹글링
- C++ 컴파일러는 오버로딩 된 함수들을 구별하기 위해서 임의로 함수들의 이름을 변경합니다.
- 예를 들어,
func(int) => _func_i
func(double, double) => _func_d_d
등과 같이 변경됩니다.
* 위치지정 new
- new를 통한 동적 할당을 원하는 곳에 할 수 있습니다.
#include <iostream>
int main()
{
char buffer1[100];
char buffer2[100];
char* A = new (buffer1) char;
int* B = new (buffer2) int;
printf("A :%p, buffer1 : %p\n", A, &buffer1);
printf("B :%p, buffer2 : %p\n", B, &buffer2);
delete[] A; //불가능
delete[] B; //불가능
return 0;
}
/*실행 후
A :000000781B9CF570, buffer1 : 000000781B9CF570
B :000000781B9CF600, buffer2 : 000000781B9CF600
*/
- 이럴 경우, 이미 사용되고 있는 메모리인지 확인하지 않기 때문에
메모리 관리 부담은 온전히 프로그래머의 것입니다.
- 정적 메모리에 할당했기 때문에, delete[] 키워드는 동작하지 않습니다.
- new의 호출 구조 : new(사이즈, 주소);
'공부 및 정리 > C++' 카테고리의 다른 글
[메모] l-value와 r-value (0) | 2022.12.20 |
---|---|
C++의 기초 - 6 (0) | 2022.12.12 |
C++의 기초 - 5 (0) | 2022.12.12 |
C++의 기초 - 4 (0) | 2022.11.30 |
C++의 기초 - 3 (0) | 2022.07.12 |