▶️ 언어는 고수준언어와 저수준 언어가 있습니다.
- 고수준언어 : 사람이 이해하기 편한 언어 ex) 자바 C# 등
- 저수준언어 : 컴퓨터가 이해하기 편한 언어 ex)어셈블리어
- 컴파일러 : 수준 언어를 저수준 언어로 번역해 주기 위한 번역기.
- 전처리기 : 컴파일 전에 처리하는 기능입니다.
- 다른 cpp 파일도 포함가능하며 헤더 파일을 포함시켜서 사용하기 위한 기능입니다. 대부분 헤더파일 포함하기 위해 사용합니다.
- ex : #include <iostream>
- #define
- include : 헤더 파일을 포함시켜서 사용하기 위한 기능입니다.
▶️ 실행 파일이 만들어지는 순서
코드 작성 -> 전처리 -> 컴파일 -> 빌드 -> 링크 -> 실행파일 제작
- 전처리 (Preprocessing) : 전처리기 구문을 전처리기로 컴파일 전 코드를 준비하고 처리하는 과정.
- 매크로 치환작업이나 전처리 구문으로 필요한 헤더 파일을 불러오고 define으로 정의한 기호 상수를 코드상에 채워 넣어주는 역할등을 진행합니다.
- 컴파일(Compilation) : 컴파일러가 전처리기가 처리해준 소스코드를 이용해서 어셈블리어로 만들어 주는 과정을 말합니다.
- 빌드 : 컴파일된 소스코드에 필요한 파일을 링크시켜주는것. 빌드 = 컴파일 + 링크
- 링크(Linking) : 컴파일된 목적파일을 실행 가능한 파일로 만들도록 연결하는 작업 입니다.
- 링커를 통해 여러 목적파일들을 하나로 결합하여 하나의 실행파일로 만듭니다.
▶️ 진입점
프로젝트의 시작점 함수입니다. 콘솔 환경에선 main() 키워드는 고정입니다.
윈도우 환경에선 winMain() 입니다.
- 한번 빌드하고 난 후(ctrl + f5)
해당 프로젝트 파일의 debug 폴더안에 들어가보면 exe파일이 생성되어 있습니다.
실행파일을 구성하고 있는 기계어코드가 메모리에 저장되고 cpu가 동작시켜주는 방식으로 실행파일이 실행하게 됩니다.
- 코드 최상단 #include <iostream>을 넣어야 합니다.
// #이 붙을 경우 전처리기
// include : 헤더파일을 포함시켜서 사용하기 위한 기능
// iostream : 표준 입출력 지원. 파일 읽어오기, 쓰기 등등 가능
#include <iostream>
- warning 줄이기 : 실무에선 특히 안뜨게 해야합니다.
-> 🐝🍯꿀팁 : 해당 워닝을 더블클릭하면 경고를 발생시키는 줄로 이동해줍니다.
#include <iostream>
using namespace std;
int main()
{
return 0;
}
- using namespace std; // std를 사용하겠다고 네임스페이스 사용 선언
위 문장을 사용할 경우 std::를 생략할 수 있습니다.
하지만 실무에서 사용하면 네이밍 충돌이 일어날 수 있기때문에 위 문장은 추천하지 않습니다.
- 문자열 출력
int main()
{
// cout : console output // dos(콘솔)창에 텍스트 출력시 사용
// ::는 범위지정연산자 (스코필드) => std안에있는 cout
// std는 namespace이다. => 구분을 지어서 사용할 수 있게 해줌
// namespace는 소속을 지정해줌. 동일한 이름이라도 소속을 지정하여 사용할 수 있게 해줍니다.
// 오른쪽에서 왼쪽으로 해석이 진행됨
// "" 안에 텍스트를 작성하는 것을 문자열이라고 합니다
// 문자열은 문자 여러개의 집합입니다
// ''안에 문자 하나를 작성할 수 있습니다
// => 오른쪽의 문자열을 cout으로 보내서 콘솔창에 출력해준다
// std::endl : 개행문자를 만들어준다
std::cout << "Output\n" << std::endl;
// c언어 스타일 출력 방식
printf("aa\n");
}
- 코드를 작성후 인텔리전스(코드가 에러가 났는지 등등을 판단해주는 기능)이 느린경우가 있습니다
ctrl + B 를 눌러서 컴파일 에러가 나는지
코드 작성 중간마다 확인해주는 습관을 기릅시다.
- 빌드 후 프로젝트 폴더안에서 일어나는 일
빌드를 하고 나면 프로젝트 폴더 안에 x64 (64비트 컴퓨터의 경우. 32비트 컴퓨터의 경우 x86으로 생성)
라는 폴더가 추가되어 있습니다.
해당 폴더안의 'Debug'폴더안에 들어가면 '프로젝트명.exe' 파일이 생성되어 있습니다.
위 코드로 작성되었을 경우 exe파일을 눌러도 실행이 되지않는것 처럼 보이지만
빠르게 실행되고 빠르게 종료되기 때문에 실행이 되지 않는것처럼 보이는것입니다.
비주얼스튜디오 상단에서 해당 옵션을 확인할 수 있습니다.
솔루션 플랫폼에서 64비트, 32비트 선택이 가능합니다
Debug : 개발용 단계에서 사용.
디버깅 툴이 포함. 용량이 큼.
Release : 최종적으로 배포 버전을 만드는데 사용
-> 작업팁 : debug로 제작 후 한개의 기능 (또는 작업단위) 완성 후 Release 버전으로 빌드하여 문제가없는지 한번씩 확인하는것이 중요합니다. debug 빌드일때 안나오는 문제가 Release 빌드에서 나오는 경우가 있기 때문입니다.
[ 변수 ]
- 메모리에 공간을 만들고 값을 저장하기 위해 사용합니다.
- 저장된 값은 필요에 따라 변경도 가능합니다.
- 저장하는 데이터의 종류에 따라 타입이 구분됩니다.
1bit : 용량의 최소 단위입니다. 0, 1 둘 중 하나를 표현할 수 있습니다
1byte : 8bit. 0, 1 둘 중 하나를 8자리로 표현할 수 있다. 2의 8승. 256개 표현 가능합니다
1kbyte : 1024byte
- 정수/실수 타입들은 unsigned 키워드를 이용해서 -부분을 +부분으로 만들 수 있습니다. (플러스만 존재)
⭐ 1byte의 표현범위는 외우는걸 추천드리며, 나머지는 대략적인 범위를 알아두길 추천드립니다.
⭐ 타입별 메모리크기는 외우길 추천드립니다.
타입 | 데이터 종류 | 메모리 크기 | 값의 표현 범위 | 기타 |
char | 문자 | 1byte | -128 ~ 127개 (0포함) | 한글이나 한문은 2byte. ⭐ 1byte 표현범위는 외우기 |
bool | 참 / 거짓 | 1byte | false(0), true(1) | 거짓을 표현할 때 0은 거짓, 0이 아닌 모든 수는 참 |
short | 정수 | 2byte | -32768 ~ 32767 | 요새는 기본이 4byte |
int | 정수 | 4byte | -2,147,483,648 ~ 2,147,483,647 | 약 - 22억 ~ 21억 |
__int64 | 정수 | 8byte | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
|
long | 정수 | 4byte | -2,147,483,648 ~ 2,147,483,647 | ✅메모리 크기 예외 : Window에선 4byte, 리눅스등 os 64x에선 8byte |
long long | 정수 | 8byte | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
|
float | 부동소수점 | 4byte | 3.4E-38(-3.4*10^38) ~ 3.4E+38(3.4*10^38) |
|
double | 부동소수점 | 8byte | 1.79E-308(-1.79*10^308) ~ 1.79E+308(1.79*10^308) |
▶️ 초기화 하지 않은 변수를 사용할 경우 컴파일 에러가 날 수 있습니다.
초기화 하지 않을 경우 변수에는 쓰레기값이 들어가게 됩니다.
int num ; // 선언만 하고 초기화하지 않음 (값을 대입하지 않음)
std::cout << num << std::endl; // 변수를 초기화하지 않고 사용을 시도하여 에러
- 표현범위를 넘어가면 한바퀴돌아서 다음값으로 출력
short num = 32768;
std::cout << num << std::endl;
결과값 :
- short이 표현할 수 있는 최대 표현범위(~32767)를 넘어섰기 때문에(오버플로)
short의 표현범위 중 제일 적은 수인 -32768이 출력됩니다.
short sh = -32769;
std::cout << sh << std::endl;
반대의 경우도 동일하게 나오는 것을 확인하실 수 있습니다.
- bool값을 출력하면 false는 0, true는 1로 출력됩니다
bool testBool = false;
std::cout << testBool << std::endl;
[ 상수 ]
- 메모리에 공간을 만들고 값을 저장하기 위해 사용.
- 저장된 값은 변경이 '불가능' 합니다.
- 변수 앞에 'const'라는 키워드를 붙여주면 상수가 됩니다.
- 선언과 동시에 초기화해주어야 합니다.
// 변수 선언 및 초기화 예시
const int numConst = 100;
// 아래 문장을 넣을 경우 에러! : 상수의 값을 변경하려 해서.
//numConst = 200;
[ 형변환 ]
- 변수 타입을 다른 타입으로 일시적으로 변경하는 기능입니다.
char testChar = 'a';
// c언어 스타일 형변환
std::cout << (int)testChar << std::endl;
// c++스타일 형변환
std::cout << static_cast<int>(testChar) << std::endl;
[ cout으로 실수 출력할때 주의사항 ]
float num3 = 3.14546546453321312f;
double num4 = 33.6654987;
// 출력 : 3.14547. cout은 최대 소수점 5개까지 출력해줌
std::cout << num3 << std::endl;
// 출력 : 33.6655. 얘는 정수앞에 자릿수가 커서리 소숫점자리수가 줄어들음
std::cout << num4 << std::endl;
- 값이 잘려보이지만 값은 그대로 가지고 있으며, 출력할때만 모든 자릿수가 출력되지 않는 상태입니다.
[ printf()를 사용하여 중간에 정수, 문자열, 실수 넣기 ]
// %d : 정수를 받아서 출력
// %s : 문자열을 받아서 출력
// %f : 실수를 받아서 출력
printf("Print Num : %d, %d\n", num, num2);
// 3.145465 출력 // 반올림 처리되어 출력
printf("Print Num3 : %f\n", num3);
// 3.145 // 소숫점 3자리까지만 출력 // %.nf 소숫점 n자리수까지 출력
printf("Print Num3 : %.3f\n", num3);
[ 실수를 정수타입 변수에 대입할 경우] : 암시적 형변환 발생
// float 타입 변수를 int 타입 변수에 대입. 형변환이 일어남. 소숫점 아래 잘림.
// 실수를 정수형 변수에 넣기
float num33 = 3.14546546453321312f;
int num6 = 0;
num6 = num33;
std::cout << num6 << std::endl; // 3 출력
- float 타입 변수를 int 타입 변수에 대입할 경우 우리 눈에는 보이지 않지만 형변환이 일어나고 있습니다.
[ 실수형 변수의 앞자리수가 늘어날 경우 ]
float num3 = 1234567.0f;
std::cout << num3 << std::endl; // 1.23457e+06 출력 // cout이 이렇게 출력해버림. 수가 큰 수라면 자동으로 지수표기법으로 변경되어버림. 하지만 실제 변수의 값은 정상적으로 가지고있음.
double num4 = 1234567.0f
std::cout<< num4 << std::endl; // 위와동일
printf( "num3 is %.3f", num3 ); // num3 is 1234567.000 출력
- cout으로 표현할 경우 위와같이 지수로 표현됩니다.
=> cout에서 float은 32비트의 메모리공간을 쪼개서 사용합니다. 정수부분을 표현하는 범위가 int보다 적기때문에 주의해야 합니다.
- 디버깅으로 num3의 값을 확인하면 값은 1234567.0이 정확히 들어가있음을 확인할 수 있습니다
- printf로 출력할 경우 정상적으로 출력됨을 확인할 수 있습니다.
[ 연산자 ]
1. 사칙연산자 : + - * / %(나머지연산자, 모드연산자). *(곱하기)와 /(나누기)가 우선순위가 높아서 먼저 계산됩니다.
10 / 3 = 3.3333
10 % 3 = 1
나머지 연산자는 정수만 계산가능 합니다.
std::cout << (1 + 5) * 3 << std::endl; // 18 출력
1) 나눗셈 사용시 주의점 : 0으로 나누기 시도시 에러가 납니다
ex) 10 / 0 <-------- 에러 !
그런데 0을 나누려 하면 에러 나지 않습니다.
ex) 0 / 10 // 0 출력
2) 나눗셈 사용시 주의점2 : 왼쪽 오른쪽값이 정수일 경우 결과값도 정수만 나옵니다
ex) 10 / 3 // 3 출력
-> 10.f / 3 // 3.33333 출력 // 실수가 필요할 경우, 둘 중 한개의 값은 실수로 바꿔주어야 합니다
2. 관계연산자 : <, >, <=, >=, ==, !=
- 값 대 값을 연산해서 결과로 참/거짓이 나오게 됩니다.
std::cout << (10 < 20) << std::endl;
std::cout << (10 > 20) << std::endl;
3. 논리연산자
: 참/거짓 연산해서 결과로 참/거짓이 나옵니다.
- OR(||) : 한개만 참이어도 참
- AND(&&) : 둘다 참이어야 참
- NOT(!) : 역
std::cout << "false || false = " << (false || false) << std::endl;
std::cout << "true || false = " << (true || false) << std::endl;
std::cout << "false || true = " << (false || true) << std::endl;
std::cout << "true || true = " << (true || true) << std::endl;
std::cout << "false && false = " << (false && false) << std::endl;
std::cout << "true && false = " << (true && false) << std::endl;
std::cout << "false && true = " << (false && true) << std::endl;
std::cout << "true && true = " << (true && true) << std::endl;
std::cout << "!true = " << (!true) << std::endl;
std::cout << "!false = " << (!false) << std::endl;
결과
- 관계 연산자가 논리 연산자보다 우선순위가 높습니다.
num1 = 85;
std::cout << "num1이 70이상이고, 90이상인지 체크 : " << (70 <= num1 && num1 <= 90) << std::endl;
[ 2진수, 10진수, 16진수 ]
- 2진수 : 0, 1 둘 중 하나의 값으로 표현하는 숫자의 집합
- 10진수 : 0 ~ 9 사이의 하나의 값으로 표현하는 숫자의 집합
- 16진수 : 0 ~ 15사이의 하나의 값으로 표현하는 숫자의 집합. 10 ~ 15 사이는 알파벳 a - f 로 표현
▶️ 10진수 471 -> 2진수로 바꾸기
471 / 2 = 235 ---- 1
235 / 2 = 117 ---- 1
117 / 2 = 58 ----- 1
58 / 2 = 29 ----- 0
29 / 2 = 14 ------ 1
14 / 2 = 7 ------- 0
7 / 2 = 3 -------- 1
3 / 2 = 1 -------- 1
몫부터 거꾸로 읽기 : 111010111
▶️ 111010111를 10진수로 바꾸기
1 1 1 0 1 0 1 1 1
256 128 64 32 16 8 4 2 1 => 위에가 1인 부분만 더워주기
= 256 + 128 + ... + 1 = 471
▶️ 10 -> 16진수로 바꾸기
- 먼저 2진수로 바꿔주기
- 16진수 1자리는 2진수 4자리로 구성
1 / 1101 / 0111 <- 뒤에부터 4자리씩 쪼개기
1 / 8421 / 8421
1 / 13 / 7
1 / d / 7
0x1d7 <= 앞에 0x붙여주기 (16진수라는것 표시)
반대로
7 / 2 = 3 ---1
3 / 2 = 1 ---1
0111
13 / 2 = 6 --- 1
6 / 2 = 3 ---- 0
3 / 2 = 1 ---- 1
1101
=> 2진수라고 쓸땐 0b 를 앞으로 붙여주면 됩니다. 근데 쓸 일은 거의없습니다.
= 111010111
==> 2진수단위 연산이 빠릅니다.
==> 최적화에 연산 단위를 바꾸는방법도 있습니다.
[ 비트단위 논리연산자 ]
- 값 대 값을 연산해서 결과로 값이 나오게 됩니다.
- OR(|), AND(&), NOT(~), XOR(^) // NOT은 암호화할때 많 이 사용합니다.
OR(|) 연산 : 값이 한개라도 1이 있으면 1, 모두 0 이면 0
471 | 217
111010111
011011001
| 111011111 => 479 (10)
AND(&) 연산 : 두 값이 모두 1이여야 1, 나머지 0
471 & 217
111010111
& 011011001
011010001 => 209 (10)
XOR 연산 : 0110 서로 값이다를때만 TRUE
1010
^0010
1000
▶️ OR, AND, XOR 연산의 활용예시
// 활용방법
int buf = 0;
const int attack = 0x1; // 1
const int defense = 0x2; // 10
const int hp = 0x4; // 100
const int mp = 0x8; // 1000
const int exp = 0x10; // 10000
// attack 버프 on
// buf = 0 | 1 = 1;
// buf |= attack; 으로도 줄여서 사용 가능
buf = buf | attatck ;
// hp 버프 on
// buf = 001 | 100 = 101 = 5
buf = buf | hp ;
// exp 버프 on
// buf = 00101 | 10000 = 10101 (2) = 21 (10) ;
buf = buf | exp;
// hp 버프 off
// buf = 10101 ^ 00100 = 10001
buf = buf ^ hp;
// 버프가 켜져있는지 확인
std::cout << "attack = " << ( buf & attack ) << std::endl;
std::cout << "defense = " << ( buf & defense ) << std::endl;
std::cout << "hp = " << ( buf & hp ) << std::endl;
std::cout << "mp = " << ( buf & mp ) << std::endl;
std::cout << "exp = " << ( buf & exp ) << std::endl;
0이 아닌 값이 들어갔을 경우 사용중이라고 판단합니다.
NOT연산
int : 32bit
~ 00000000 00000000 00000001 11010111
11111111 11111111 11111110 00101000 => 맨 첫자리는 부호비트
not은 거어어어의 쓰이지않음 보안에 쓰인다고 합니다
std::cout << ~471 << std::endl;
[ 시프트 연산자 ]
- <<, >>
- 값대 값을 연산하여 결과로 값이 나오게 됩니다.
- cout 에서 사용하는 <<는 쉬프트연산자로 사용하는게 아니라 연산자를 재정의하여 사용하는 것입니다.
- 빠른 곱하기 연산. 2의 n승 단위의 곱셈만 가능.
▶️ 왼쪽 시프트 연산
10은 2진수로 1010이다.
10 << 2 = 40 (왼쪽 쉬프트연산) (10 곱하기 2의 2승과 같음)
1010을 왼쪽으로 두칸 이동 시키란 의미
1010 뒤에 0을 두개 붙이란 의미와 같습니다.
101000이 된다.
10 << 3 = 80 (10 곱하기 2의 3승과 같음)
1010000
=> 왼쪽 시프트 연산은 2의 n승 단위의 곱셈 입니다
▶️ 오른쪽 시프트 연산
80 >> 2 = 20
1010000 을 오른쪽으로 2칸 이동하라는 의미로
1010000 오른쪽 2개의 숫자를 없얘는 것과 같습니다.
10100
80 >>> 3 = 10
1010
오른쪽 시프트 연산은 2의 n승 단위의 나눗셈 입니다
가독성은 좋지 않지만 속도는 빠릅니다.
그래픽스에서 자주 사용합니다. 신입에게 렌더링 맡기면 튀튀합시다
▶️ 시프트 연산 사용예시
#include <iostream>
int main()
{
// a | r | g | b 형식으로 color에 값을 저장
// 0 | 0 | 0 | 0
unsigned int color = 0; // 4byte
unsigned char r = 255; // 1byte
unsigned char g = 80;
unsigned char b = 102;
unsigned char a = 37;
color = a; // 0 | 0 | 0 | a
color = color << 8; // 0 | 0 | a | 0 // 1byte = 8bit
color = color | r; // 0 | 0 | a | r
color = color << 8; // 0 | a | r | 0
color = color | g; // 0 | a | r | g
color = color << 8; // a | r | g | 0
color = color | b; // a | r | g | b
std::cout << color << std::endl;
// 뽑아내기 : & 연산 b 만 뽑아낼 경우 = color & 1111 1111
std::cout << "b = " << (color & 0x000000ff) << std::endl;
// g 뽑기
std::cout << "g = " << ((color >> 8) & 0x000000ff) << std::endl;
std::cout << "r = " << ((color >> 16) & 0x000000ff) << std::endl;
std::cout << "a = " << ((color >> 24) & 0x000000ff) << std::endl;
// buf = buf & attack ;
// buf &= attack ; // 누적 연산 가능 (사칙 다됨 관계 연산자는 다 된다고 생각하기)
num1 = 100;
num1 += 30; // num1 = num1 + 30;
return 0;
}
'개발개발 > c++' 카테고리의 다른 글
c++의 include define, extern, memcpy_s (0) | 2024.12.09 |
---|---|
c++의 지역변수, 전역변수, 메모리 영역, static 변수, 동적할당, 함수 오버로딩, 함수의 디폴트 인자 (0) | 2024.12.08 |
c++의 구조체, 구조체 크기와 구조체 멤버맞춤 (0) | 2024.12.07 |
c++의 함수 (0) | 2024.12.06 |
c++의 조건문, 난수, 사용자 정의 변수타입, enum class, 반복문, 배열 (1) | 2024.12.05 |
댓글