#include <stdio.h>
// 전역변수
int main()
{
// 지역변수
}
🔷 변수의 종류
1. 지역 변수 (Local Variable)
함수 또는 블록 내부에서 선언됨.
해당 블록이 끝나면 메모리에서 자동으로 해제됨.
void func() {
int a = 10; // 지역 변수
} // 함수가 끝나면 a는 사라짐
2. 전역 변수 (Global Variable)
함수 외부에서 선언되며, 프로그램 전체에서 접근 가능함.
데이터 영역에 저장되어 프로그램 종료 시까지 유지됨.
int globalVar = 20; // 전역 변수
void func() {
globalVar += 5; // 어디서든 접근 가능
}
3. 정적 변수 (Static Variable)
지역 변수처럼 보이지만, 데이터 영역에 저장되어 프로그램 종료 시까지 유지됨.
함수가 여러 번 호출되어도 이전 값을 유지함.
void counter() {
static int count = 0; // 정적 변수
count++;
printf("%d\n", count);
}
int main() {
counter(); // 1
counter(); // 2
counter(); // 3
}
4. 외부 변수 (Extern Variable)
다른 파일에서 선언된 전역 변수를 참조할 때 사용됨.
extern 키워드를 사용하여 연결 가능.
// a.cpp 파일
int num = 10; // 외부 변수
// b.cpp 파일
extern int num; // a.cpp의 num을 참조
🔷 C++에서 기능을 헤더 파일과 분리하기
새 파일 (해더파일) 생성 ctrl + shift + A
매인.cpp파일말고 새 cpp 파일 생성하면 소스파일에 들어감.
1. 헤더 파일에 함수 선언만 포함하기
// function.h
#ifndef FUNCTION_H
#define FUNCTION_H
int add(int a, int b); // 함수 선언
#endif
2. 동일한 이름의 .cpp 파일에 함수 정의 작성하기
// function.cpp
#include "function.h"
int add(int a, int b) {
return a + b;
}
3. main.cpp에서 함수 사용하기
// main.cpp
#include <stdio.h>
#include "function.h"
int main() {
int result = add(3, 5);
printf("결과: %d\n", result);
return 0;
}
4. 컴파일 과정과 링크 과정
- 컴파일 시 function.cpp의 함수 구현이 function.obj 파일로 저장됨.
- main.cpp에서 add 함수 호출 정보가 main.obj에 저장됨.
- 링크(Linking) 과정에서 두 개의 객체 파일(function.obj과 main.obj)이 합쳐져 실행 파일이 생성됨.
헤더 파일 분리 시 발생할 수 있는 오류
1. 함수 정의를 헤더 파일에 포함하는 경우 (중복 정의 오류)
잘못된 코드
// function.h
int add(int a, int b) { return a + b; } // 잘못된 코드
오류 발생 이유
- #include "function.h"가 여러 곳에서 사용되면 add 함수의 정의가 중복됨.
- 링커 단계에서 "multiple definition" 오류 발생.
해결책
- 헤더 파일에는 함수 선언만 포함하고, 정의는 별도의 .cpp 파일에 작성.
2. #include의 역할과 문제점
#include의 역할
- #include는 지정된 파일의 내용을 그대로 복사하여 붙여넣는 역할.
문제점
- 함수 정의가 헤더 파일에 포함되면, 여러 파일에서 #include될 때 중복 오류 발생.
3. 함수 정의가 여러 곳에 존재할 때의 문제
예제 코드
// function.h
int add(int a, int b); // 선언만 포함
// main.cpp
#include "function.h"
int add(int a, int b) { return a + b; } // main.cpp에서 정의
문제점
- 다른 .cpp 파일에서도 같은 함수 정의가 존재하면 중복 오류 발생.
해결책
- 함수의 정의는 하나의 소스 파일에만 존재해야 함.
4. 링크 오류(LNK 오류) 발생 원인
1) 함수 선언만 있고 정의가 없는 경우
예제 코드
// function.h
void myFunction(); // 선언만 있음
// main.cpp
#include "function.h"
int main() {
myFunction(); // LNK 오류 발생 (정의 없음)
return 0;
}
해결책
- function.cpp에서 정의 추가.
2) 구현된 소스 파일이 링크 대상에서 누락된 경우
- 함수가 function.cpp에 정의되어 있지만, 컴파일 시 function.cpp를 빌드 대상에 포함하지 않으면 링크 오류 발생.
해결책
- 프로젝트 설정에서 .cpp 파일이 빌드 대상에 포함되었는지 확인.
3) 함수 선언과 정의의 불일치
잘못된 코드
// function.h
void myFunction(int x); // 선언
// function.cpp
void myFunction() { // 정의 (잘못됨)
// ...
}
해결책
- 함수의 선언과 정의가 동일한 매개변수 리스트를 가져야 함.
5. 전역 변수 사용 시 주의할 점
1) 잘못된 방법: 헤더 파일에서 전역 변수 선언
// wrong.h
int globalVar = 10; // 잘못된 코드
문제점
- #include "wrong.h"가 여러 곳에서 사용되면, globalVar가 중복 선언됨.
해결책
- extern 키워드를 사용하여 선언만 하고, 정의는 한 곳에서만 작성.
2) 올바른 방법: extern 사용
선언 (global.h)
#ifndef GLOBAL_H
#define GLOBAL_H
extern int globalVar; // 선언만 포함
#endif
정의 (global.cpp)
int globalVar = 10; // 정의
사용 (main.cpp)
#include "global.h"
int main() {
globalVar += 5;
return 0;
}
장점
- global.h에서 extern을 사용해 전역 변수 선언만 포함.
- global.cpp에서 전역 변수를 정의하여 한 번만 생성되도록 함.
6. 함수의 전역 변수 사용 방법
1) 잘못된 방법: 헤더 파일에 전역 변수 선언
// global.h
int globalVar = 10; // 잘못된 방법
문제점
- #include를 사용하여 여러 파일에서 포함하면, globalVar가 중복 선언됨.
2) 올바른 방법: extern 선언 후, 정의는 한 곳에만
선언 (global.h)
#ifndef GLOBAL_H
#define GLOBAL_H
extern int globalVar;
#endif
정의 (global.cpp)
int globalVar = 10; // 정의
사용 (main.cpp)
#include "global.h"
int main() {
globalVar += 5; // 사용 가능
return 0;
}
3) 함수에 전역 변수를 전달하는 방법
void updateGlobal(int& value) {
value += 10;
}
int main() {
int globalVar = 5;
updateGlobal(globalVar);
return 0;
}
장점
- 전역 변수를 직접 사용하지 않고, 함수의 인자로 전달하여 사용 가능.
🔷정적 변수 (Static Variable) & 외부 변수 (Extern Variable)
문제 상황
헤더 파일과 소스 파일을 분리하여 구현하는 과정에서, 전역 변수를 선언한 후 다른 파일에서 구현한 함수에서 이를 사용할 수 없는 문제가 발생함.
목표
전역 변수를 모든 .cpp 파일에서 인식하도록 설정.
⚠ 주의: 동일한 전역 변수를 여러 파일에서 선언하면 컴파일 단계에서는 오류가 발생하지 않지만, 링크 단계에서 중복 선언 오류가 발생함.
정적 변수 (Static Variable)
개념
정적 변수는 함수 내 또는 함수 밖에서 선언될 수 있으며, 데이터 영역에 저장되어 프로그램이 종료될 때까지 유지됨. C++에서 static의 의미는 "선언된 영역을 벗어나지 않는다"는 것.
특징
- 파일 내에서만 사용 가능: static으로 선언된 변수는 선언된 파일 내에서만 접근 가능.
- 함수 내에서 유지: 함수 내부에 선언된 static 변수는 함수가 여러 번 호출되어도 값을 유지함.
- 초기화 이후 유지: 최초 호출 시 한 번만 초기화되며, 이후에는 값을 유지한 채로 함수 호출 가능.
기본 형태
void counter() {
static int count = 0; // 정적 변수
count++;
printf("%d\n", count);
}
int main() {
counter(); // 1
counter(); // 2
counter(); // 3
return 0;
}
선언 위치에 따른 차이점
선언 위치 | 특징 | 차이점 | 공통점 |
전역 (static 전역 변수) |
파일 내부에서만 접근 가능 (internal linkage) | 같은 파일 내의 다른 함수에서 접근 가능하지만, 다른 파일에서는 접근 불가 | 프로그램 시작 시 생성되고 종료 시 소멸 |
클래스 (static 멤버 변수) |
모든 객체가 공유하는 변수 | 객체 없이 ClassName::variableName으로 접근 | 프로그램 실행 중 한 번만 생성, 종료될 때까지 유지 |
함수 내부 (static 지역 변수) |
호출될 때마다 같은 값 유지 | 함수가 끝나도 소멸되지 않고 유지 | 함수 내부에서만 접근 가능 |
네임스페이스 내부 (static 변수) |
해당 네임스페이스 안에서만 유효 | 전역 static 변수와 유사하게 외부 접근 불가 | 프로그램 시작 시 생성되고 종료 시 소멸 |
정적 함수와 일반 함수의 차이
정적 함수는 전역 함수의 사용 가능 영역을 제한한 것과 유사하며, 기능과 접근을 제한하는 것도 기능의 일부가 될 수 있음.
정적 변수 예제
#include <stdio.h>
#include "function.h"
int test() {
static int i = 0;
i++;
return i;
}
int main() {
test(); test(); test(); test();
int iCall = test();
printf("결과: %d\n", iCall); // 출력: 결과: 5
return 0;
}
모든 파일에서 접근 가능한 공통 변수 설정 방법
잘못된 방식
static을 사용하여 common.h에서 변수를 선언하면, 각 파일에서 별도의 정적 변수로 취급됨.
// common.h
#pragma once
static int g_iStatic = 0; // 각 파일마다 다른 변수로 인식됨
올바른 방식: extern 키워드 사용
공통으로 사용할 전역 변수는 extern 키워드를 사용하여 선언해야 함.
// common.h
#pragma once
extern int g_iGlobal;
// common.cpp
#include "common.h"
int g_iGlobal = 0; // 실제 변수 정의
// main.cpp
#include <stdio.h>
#include "common.h"
int main() {
g_iGlobal = 10;
printf("g_iGlobal: %d\n", g_iGlobal);
return 0;
}
정리
- static 변수는 파일 내부 또는 함수 내부에서만 유지됨.
- 모든 파일에서 공통으로 사용할 변수는 extern을 사용하여 선언해야 함.
외부 변수(Extern Variable)
외부 변수(Extern Variable)는 여러 소스 파일에서 공유하는 전역 변수를 정의할 때 사용됩니다.
즉, 한 곳에서 변수를 초기화(정의)하고, 다른 파일에서는 해당 변수를 참조할 때 사용하도록 '알려주는(선언하는)' 역할을 합니다.
외부 변수의 주요 특징
- 선언과 정의의 구분:
- 선언(Declaration): 변수의 이름과 타입을 알려주지만, 메모리를 할당하거나 초기화하지 않습니다.
- extern int i_extern; 처럼 선언만 해두면, 해당 변수의 정의는 다른 파일에서 이루어져야 합니다.
- 정의(Definition): 변수에 실제 메모리를 할당하고, 초기값을 지정합니다.
- 예를 들어, int i_extern = 0;처럼 한 번 정의되어야 합니다.
- 선언(Declaration): 변수의 이름과 타입을 알려주지만, 메모리를 할당하거나 초기화하지 않습니다.
- 링크 에러 방지:
- 변수의 정의가 여러 곳에서 이루어지면, 링크 단계에서 중복 정의 오류가 발생합니다.
- 따라서 선언은 헤더 파일에서, 정의는 단 한 곳(예: 별도의 소스 파일)에서 해야 합니다.
언제, 어떻게 사용하는가?
- 여러 파일에서 동일한 전역 데이터를 공유할 때:
- 프로그램의 여러 부분이 동일한 데이터를 읽거나 수정해야 하는 경우, 외부 변수를 사용하면 코드의 일관성을 유지할 수 있습니다.
- 헤더 파일에 선언, 소스 파일에 정의:
- 헤더 파일(common.h)에 extern 키워드를 사용하여 변수의 선언을 작성합니다.
- 단, 변수의 초기화(정의)는 반드시 하나의 소스 파일(예: somewhere.cpp)에서 수행합니다.
- 사용 예시:
- 프로그램의 시작점인 main.cpp와 같이 여러 파일에서 동일한 전역 변수에 접근하여 값을 변경하거나 확인할 수 있습니다.
예시 코드
1. 헤더 파일 (common.h)
#ifndef COMMON_H
#define COMMON_H
// 외부 변수 i_extern의 선언. 다른 파일에서 정의된 전역 변수임을 알림.
extern int i_extern;
#endif // COMMON_H
2. 변수 정의 및 초기화 (somewhere.cpp)
#include "common.h"
// 전역 변수 i_extern의 정의 및 초기화. 이 부분이 반드시 한 번만 실행되어야 함.
int i_extern = 0;
3. 변수 사용 (main.cpp)
#include <iostream>
#include "common.h" // 외부 변수 i_extern의 선언이 포함된 헤더 파일
int main() {
// 외부 변수 i_extern의 값을 1 증가시킴.
i_extern++;
// 외부 변수의 현재 값을 출력.
std::cout << "i_extern의 값: " << i_extern << std::endl;
return 0;
}
요약
- 외부 변수는 여러 소스 파일에서 공유되는 전역 변수로, 선언과 정의를 분리하여 사용합니다.
- 헤더 파일에는 extern 키워드를 사용하여 변수의 선언만 포함시키고, 하나의 소스 파일에서 반드시 변수의 정의와 초기화를 해야 합니다.
- 이 방식을 통해 여러 파일 간의 데이터 공유를 가능하게 하고, 링크 단계에서 발생할 수 있는 중복 정의 오류를 방지할 수 있습니다.
외부 변수의 선언과 정의를 분리하는 이유
- 역할 분담:
헤더 파일에서는 변수의 선언만을 수행하여 다른 파일들이 해당 변수의 타입과 이름을 인식할 수 있도록 합니다. 실제 메모리 할당과 초기화는 단 하나의 소스 파일에서 정의를 통해 이루어집니다. 이로써, 여러 파일이 하나의 공통 변수를 참조할 수 있습니다. - 유지보수와 코드 관리:
변수의 선언과 정의를 명확하게 분리하면, 코드의 구조가 더욱 명료해지고 수정 시 한 곳만 변경하면 되기 때문에 유지보수가 쉬워집니다.
이처럼, 외부 변수의 선언과 정의를 분리함으로써 여러 파일에서 공통 데이터를 안전하게 공유하고, 프로그램의 안정성과 관리 효율성을 높일 수 있습니다.
메모리 영역 (Memory Sections)
스택(Stack) 영역
지역 변수, 함수 호출 시 생성되는 메모리가 저장됨.
함수가 끝나면 자동으로 해제됨.
LIFO (Last In, First Out) 방식으로 동작.
데이터(Data) 영역
전역 변수, 정적 변수가 저장됨.
프로그램 실행 내내 존재하며, 프로그램이 종료될 때 해제됨.
초기화된 데이터(.data), 초기화되지 않은 데이터(.bss)로 나뉨.
코드(Code) / 읽기 전용(ROM) 영역
실행할 코드가 저장되는 영역.
일반적으로 읽기 전용으로 설정되어 변조할 수 없음.
힙(Heap) 영역
new, malloc() 등을 사용해 동적으로 할당된 메모리가 저장됨.
프로그래머가 직접 해제해야 함 (delete, free()).
int* ptr = new int(10); // 힙에 메모리 할당
delete ptr; // 해제하지 않으면 메모리 누수 발생
'C++ > 유튜브 어소트락 게임아카데미 C++무료강의' 카테고리의 다른 글
8. 포인터 (0) | 2025.04.03 |
---|---|
6. 구조체(Structure) (0) | 2025.03.30 |
5. 배열 (0) | 2025.03.26 |
4 함수 (0) | 2025.03.26 |
3. 연산자 및 전처리 구문 (0) | 2025.03.24 |