void MonsterMove() // 함수
{
int MonsterSpeed = 1; // 변수
}
int main()
{
MonsterMove(); // 실행!
}
대부분의 프로그래밍 언어, 그 중에서도 객체지향을 포함한 언어들은 개념, 행동, 상태로 인간이 만들고자 하는 것을 표현한다.
int MonsterSpeed = 3;
int MonsterSpeed = 5; // 불가능!
같은 이름의 변수를 두 번 이상 선언할 수 없다.
void MonsterMove()
{
int MonsterSpeed = 3; // int MonsterMoveMonsterSpeed = 3;
}
int main()
{
int MonsterSpeed = 3; // int mainMonsterSpeed = 3;
MonsterMove();
}
이 경우에는 두가지 이유로 변수를 같은 이름으로 선언해도 빌드가 가능하다.
변수의 생략된 이름
함수의 메모리
#include <iostream>
// 전역 : 어떠한 { } 에도 속하지 않는 영역
int GlobalA = 10; // 전역변수
// 클래스 내부지역 : NOT YET
void Test()
{
// 지역 : 함수의 { } 에 속하는 영역
int LocalA = 10; // 지역변수
}
int main()
{
Test();
// 함수를 만들면 반드시 사용해보자!
// 사용하지 않은 함수는 최적화에 의하여 빌드에 포함되지 않아 오류가 있는지 없는지 알 수 없다.
}
int MonsterSpeed = 10;
void MonsterMove()
{
MonsterSpeed = 8;
}
int main()
{
MonsterSpeed = 20;
}
전역변수는 어느 지역에서도 사용 가능하다.
📢 코딩스탠다드 (추후에 추가!)
표기법 및 구분법을 각 회사나 프로젝트 상황에 맞추어 규칙을 정한 것 (가급적 유지하자!)
적어도 이 수업을 듣는 동안은… [구글 스타일 가이드 + 언리얼식]1. 전역변수와 지역변수는 이름을 구분하여 작성할 것
2. 변수에는 반드시 초기값을 설정할 것
{ } : 스코프 (레인지?)
int main()
{
// 이름 없는 메모리 영역을 만드는 것도 가능하다.
{
int Value = 0;
}
Value = 20; // 불가능!
}
스코프가 닫힐 때 할당된 메모리도 삭제되므로 지역 바깥에서는 사용할 수 없다.
int main()
{
int Value = 0;
{
Value = 20; // 가능!
}
}
이름없는 영역의 메모리는 main 함수의 메모리가 연장되는 형태이므로 이 경우에는 사용 가능하다.
변수를 사용해서 특정한 결과를 리턴하는 것
💡 연산자의 종류
산술 연산자 / 비교 연산자 / 관계 연산자 / 비트 연산자
복합 할당 연산자 / 멤버와 포인터 연산자 (포인터 배운 이후에) / 기타 연산자
변수의 개수에 따라서 분류할 수도 있다.
- 단항 연산자 : 변수가 1개 필요한 연산자 e.g.!Left;
- 이항 연산자 : 변수가 2개 필요한 연산자 e.g.Left + Right;
- 삼항 연산자 : 변수가 3개 필요한 연산자 (딱 한 종류 뿐!) e.g.Left == Right ? true : false;
📢 코드 읽기 규칙
1. 기본적으로 위에서부터 아래로 읽는다.
2. 오른쪽에서 왼쪽으로 읽는다.int Left = 3; /* 1. 3을 준비한다 2. 대입연산자를 준비한다 3. left를 만든다 4. 대입한다 */
- (2)에서 예외 : ( ) 안에 있는 내용은 우선적으로 진행된다.
int Left = 3;
int Right = 5;
int Result = 0;
// [대입] : 오른쪽의 메모리를 왼쪽의 메모리로 복사한다.
Left = Right; // 5
Result = Left + Right; // 8 => [덧셈]
Result = Left - Right; // -2 => [뺄셈]
Result = Left * Right; // 15 => [곱셈]
Result = Left / Right; // 0 => [나눗셈(몫)]
Result = Left % Right; // 3 => [나머지]
// [논리형 상수 bool] => true와 false가 있다.
bool bResult = false;
bResult = Left == Right; // false
bResult = Left != Right; // true
bResult = Left > Right; // false
bResult = Left < Right; // true
bResult = Left >= Right; // false
bResult = Left <= Right; // true
Result = Left == Right; // 0
// 사실 이렇게 정수로 결과값을 받을 수도 있다. => true 1, false 0
// 하지만 정수(int)는 4byte, 논리형(bool)은 1byte라는 차이가 있고, bool로 받는게 정석이다.
자료형을 비트 단위로 생각하는 것이 중요하다. (1 byte = 8 bit)
참 ⇒ 단 하나의 비트라도 1일 때
거짓 ⇒ 모든 비트가 0일 때
bResult = Left; // true
bResult = 0; // false
// 오로지 0만이 거짓이고, 나머지 모든 숫자는 참이다.
// 따라서 모든 값은 논리형이 될 수 있다.
// [논리 부정]
bResult = !Left; // false
// [논리적 AND] : 왼쪽과 오른쪽 메모리가 모두 true여야 true
bResult = Left && Right; // true
bResult = false && Right; // false
bResult = Left && false; // false
bResult = false && false; // false
// [논리적 OR] :: 왼쪽과 오른쪽 메모리 중 한쪽이라도 true면 true
bResult = Left || Right; // true
bResult = false || Right; // true
bResult = Left || false; // true
bResult = false || false; // false
정수의 비트표현식을 이해해야 한다.
int ⇒ 4 byte = 32 bit
Left = 0b00000000000000000000000000000000; // 2진수(binary)로 표현하겠다는 뜻
// [보수]
Left = ~0b00000000000000000000000000000000; // 0b11111111111111111111111111111111 // -1
💡 2의 보수법
비트로 음수를 표현하기 위해, 가장 앞의 비트(부호비트)가 1일 때가 음수라고 정해두었다.
하지만 -0 이라는 숫자는 존재하지 않기 때문에, 2의 보수법을 사용하기로 했다.1. 가장 앞 비트가 1인 경우, 음수이다. 2. 나머지 비트를 모두 반전시킨다. (0 → 1, 1 → 0) 3. 나머지 비트를 모두 더한 숫자에 1을 더해준다. 4. (3)의 결과물을 음수로 변환하면 짜잔!
Left = 0b00000000000000000000000000000011;
Right = 0b00000000000000000000000000000001;
// 비트 AND : 왼쪽과 오른쪽을 비교해서 둘 다 1이어야 1
Result = Left & Right; // 0b00000000000000000000000000000001 // 1
// 비트 OR : 왼쪽과 오른쪽을 비교해서 둘 중 하나만 1이어도 1
Result = Left | Right; // 0b00000000000000000000000000000011 // 3
// 배타적 논리합 : 양쪽의 비트가 같으면 0, 양쪽의 비트가 다르면 1
Result = Left ^ Right; // 0b00000000000000000000000000000010 // 2
// 비트 시프트
Result = Left << 1; // 0b00000000000000000000000000000010 // 2
Result = Left >> 1; // 0b00000000000000000000000000000000 or 0b10000000000000000000000000000000
// CPU 칩셋, 또는 VS 설정 등에 따라 결과가 달라질 수 있다.
// 아무튼 비트가 손상(?)될 수 있을만한 경우에 시프트 연산은 사용하지 않는 편이 편하다...
비트 연산은 클라이언트보다는, 대규모 유저를 감당해야 하는 서버 파트에서 좀 더 중요하다.
// Q) 비트 연산으로 -1을 만들고, 그걸 이용해서 int의 양수 최대값과 음수 최소값을 만들어보자.
int main()
{
int a = 0; // 0b 00000000 00000000 00000000 00000000
int result = 0;
int b = ~a; // 0b 11111111 11111111 11111111 11111111 => -1
a = b << 31; // 0b 10000000 00000000 00000000 00000000 => 음수 최소값
result = a ^ b; // 0b 01111111 11111111 11111111 11111111 => 양수 최대값
// 왜인지 왼쪽으로 비트를 밀어버리는건 생각하는대로 작동한다?!
return 0;
}
📢 중단점과 디버깅
코드를 보다가 현재까지 진행한 단계와 그 상태에서의 값을 확인하고 싶을 때, 확인하고 싶은 코드 라인 1줄 아래에서 F9을 누르면 중단점이 걸린다. (빨간 점)
실행 대기 중인 라인은 노란 화살표로 표시되어 있다.이 때, VS로 코드를 실행시키고 확인하기 위한 단축키도 여러 종류가 있다.
F5 ⇒ 중단점까지 진행
F10 ⇒ 한줄씩 진행, but 다른 함수의 스택에 들어가지 않는다.
F11 ⇒ 한줄씩 진행, 다른 함수가 있다면 그 함수의 내부스택까지 들어간다.F10, F11을 이용하면 아무리 복잡한 프로세스여도 시작 지점(진입점)을 알 수 있어 유용하다.
그리고 중간중간 값을 확인하는 습관은 기본 중의 기본이다!
📚 오늘의 자투리 지식
잊지 말자 기초 지식!
- 윈도우 재설치하는 법
- 하드디스크 초기화, 인식시키는 법1. 하드디스크 파티션 만들기 및 포맷 2. (인식 안된) 디스크 초기화 3. mrv 디스크로 변환 4. 새 스팬 볼륨?
C++의 버전
- C++는 연도로 버전을 구분한다.
- VS의 C++ 컴파일러는 C++ 표준과 아주 사알짝 다르다.