넣어준 글자를 출력해주는 함수.
printf는 C에서 사용하던 출력 함수다. 내부 내용이 C스타일로 짜여져 있다.
extern "C"
: 이부분을 컴파일 C스타일로 컴파일 해줘.
inline
: 치환(해줄 수 있니?라는 느낌). 컴파일러의 판단하에 이 함수의 내용을 그대로 복사해서 넣을 수 있다면 이 함수가 실행된 위치에 코드를 복사하고 실행시킴. (가장 빠른 프로그램은 main에 모든 코드를 집어넣은 프로그램이다라는 농담이 있다고 함)
int
: 리턴값
__cdecl
: 함수호출규약, 우리가 함수 만들 때도 자동으로 붙음(생략되어서 안 보임)
함수라는 것은 CPU에 요청되는 것이고 스택메모리를 사용한다. 함수호출규약은 컴파일러가 알아서 붙여준다. 기계어로 함수를 호출하면 호출자와 정리자 인자 넘기기 등을 직접 다 해줘야 하는데 그럴 때 함수호출규약마다 따로 쳐줘야한다.
전역함수는 대부분 __cdecl
을 사용한다. static 멤버함수는 __stdcall
을 사용하고 일반 멤버함수는 __thiscall
(c++전용)을 사용한다. 억지로 함수의 call 방식을 바꿀 수 있지만 그걸 바꾸면 문제가 생길 수 있다.
int main() {
Test();
return 0;
}
Test함수의 caller(호출자)는 main이다.
https://learn.microsoft.com/ko-kr/cpp/cpp/cdecl?view=msvc-170
printf_s
: 이름
const char* _Format,
: 전달한 문자열 인자를 const로 받기 때문에 변형될 일 없다.
...
: 가변인자
printf_s의 리턴값
printf_s는 화면에 출력되는 문자열의 길이를 반환한다.
const int Value = 0; // 4바이트의 영역에서 1비트도 고칠 수 없다.
이 변수의 값을 변경할 수 없다.
참조형(포인터나 레퍼런스)을 인자로 받는 함수가 참조형에 const를 안 걸어놨다면 무조건 값이 수정되어서 나올 수 있다는 의미로 받아들인다.
예를 들어 아래 StringCount함수는 글자 수를 세는 함수이지만 원본의 값을 바꿀 수 있다.(X)
const가 붙어있지 않으면 값이 바뀌어 나온다는 것을 암묵적으로 의미한다. 하지만 바뀌지 않아야 의도에 맞기 때문에 const를 붙임으로써 사용자가 넣어준 값이 바뀌지 않을 것이라는 것을 명시해준 것이다.
// XXXXXXXX
int StringCount(char* _Ptr) {
int Count = 0;
while (_Ptr[Count]) {
_Ptr[Count] = 'b';
++Count;
}
return Count;
}
// OOOOOOOO
int StringCount(const char* _Ptr) {
int Count = 0;
while (_Ptr[Count]) {
++Count;
}
return Count;
}
const char[6]
의 형태를 넣어주는 것이 된다. "aaaaaa"를 넣을 수 있게 하려면 함수의 인자에 const를 붙여줘야 한다.const 없음 | const 있음 |
---|---|
![]() | ![]() |
const 없는 참조형 자료형에 const를 붙여주는건 가능하지만, const 붙어있는 참조형 자료형에서 const를 떼는 것은 불가능하다. (const_cast라는 특별한 방법을 사용해서 뗄 수 있지만 선생님은 절대로 절대로 사용하지 않으신다고 함)
int* 자료형에 const를 붙여 사용해보았다.
그럼 600번지라는 것을 수정못하게 하려면 어떻게 해야할까?
뒤에 const를 붙이면 된다.
문자 표현 방식
abcde ㄱㄴㄷㄹ <- 인간이 보기 편하게 만든 디스플레이적인 내용일뿐이다.
글자에 대한 모든 권한은 OS가 갖고 있다.
우리가 char을 사용한다고 하면 c++이 운영체제에게 "이거 글자야" 라고 알린다.
8비트로 이루어진 램 안의 특정 메모리 영역을 글자로 바꿔주는 것이다.
8비트의 메모리 상태는 결국 2진수일뿐이다. 그러므로 char는 곧 숫자(정수)라고 할 수 있다.
함수의 인자는 일반적으로 내가 정해준 개수만큼만 넣어줄 수 있고 내가 정한 개수보다 많게 넣어도 에러, 적게 넣어도 에러다.
가변인자란 인자의 개수를 정하지 않고 사용하는 함수 인자이다. 내가 인자를 넣어주는 순간 이 함수를 지우고 그 인자 개수만큼의 함수를 만든다.
void VarTest(...) {
}
함수 매개변수들은 8바이트씩 떨어져있다. 이유는 C++의 어떤 자료형도 8바이트보다 크지 않기 때문이다. (그렇다고 4바이트짜리 int형 인자의 크기가 8바이트가 된다는 건 아니다.) 첫번째 인자의 주소와 넣은 인자의 개수만 알면 주소를 모두 알 수 있다.
그래서 가변인자의 값을 이렇게 사용할 수 있다.
void VarCountCheck(int Count, ...) {
int* Ptr = &Count;
// 포인터의 더하기는 내 현재위치 + sizeof(자료형) * 넣어준 정수.
for (int i = 0; i < Count; i++) {
Ptr += 2; // 8바이트 이동한 것임.
int Value = *Ptr;
}
}
그런데 인자의 개수를 사용자가 직접 입력하게 하는 것은 위험하다는 한계점이 있다.
가변인자에 nullptr가 들어가는 등의 위험성도 있다.
printf_s("%d count %d", 999); //가변인자의 개수를 맞추지 못하면
//두번째 %d에는 의도치않은 메모리 영역을 읽어오게 된다.
이제 printf함수를 직접 만들 수 있다. (내일)
우리반 코딩 스탠다드
- 전역변수와 지역변수 이름 무조건 다르게 하기. ex) GlobalA, LocalA
- 무조건 초기값을 설정한다.
- 함수의 인자에는 앞에 언더바
_
를 붙인다.- 포인터를 초기화할 때 0을 사용하지 않는다.
- 경로 및 함수 변수 한글 절대 금지
- 바탕화면에 프로젝트 절대 금지 있으면 평가에 반영하겠음
- 중괄호 위치 신경 안 씀, 중괄호 생략은 X (한줄로치는거 X)
- const_cast 절대 절대 사용 X.
StringToNumber함수와 NumberToString함수 만들기.
#include <iostream>
int StringCount(const char* const _Ptr)
{
int Count = 0;
while (_Ptr[Count])
{
++Count;
}
return Count;
}
void NumberToString(int Number, char* _Ptr) {
int count = 0;
int num = Number;
// count 구하기
// 맨 앞에 0이 들어가면 count가 잘못됨!!!!!!!!!!!
// 맨 앞에 0이 붙으면 8진수라서 그럼... 10진수만 생각하면 될듯?
while (num) {
num /= 10;
count++;
}
// 뒷자리부터 채우기
//while (Number) {
// int ch = Number % 10;
// _Ptr[count - 1] = ch + '0';
// count--;
// Number /= 10;
//}
// while문으로 돌면 맨 앞이 0이면 끝나버림
for (int i = count - 1; i >= 0; i--) {
int ch = Number % 10;
_Ptr[i] = ch + '0';
Number /= 10;
}
}
int StringToNumber(const char* const _NumberString)
{
// 글자 개수를 알아내야 합니다.
// StringCount();
// * 10 써야 합니다.
// / 10 써야 합니다.
// = 변수 - '0' 사용.
// for문을 사용해야합니다.
// 예외처리 안합니다.
// char Ch = _NumberString[0];
int result = 0;
int count = StringCount(_NumberString);
int power = 1;
for (int j = 0; j < count; j++) {
power *= 10;
}
for (int i = 0; i < count; i++) {
int ch = _NumberString[i] - '0';
power /= 10;
result += ch * power;
}
return result;
}
int main()
{
int Number = StringToNumber("123454321"); // 문자열이 그대로 숫자가 되어 나오는 함수를 만들면 됨
char Arr[100] = {};
NumberToString(1023450, Arr);
return 0;
}
선생님의 NumberToString 코드
void NumberToString2(int Number, char* _Ptr) {
//어떤 함수든 원본값을 보존해 놓는게 좋습니다.
int CalNumber = Number;
int NumberCount = 0;
const char* CPtr = _Ptr;
//정수가 몇자리인지 알아야 합니다.
//10나누기를 합니다.
while (CalNumber) {
CalNumber /= 10;
++NumberCount;
}
int power = 1;
for (int j = 0; j < NumberCount; j++) {
power *= 10;
}
//숫자를 분해하기 시작
//0 나누기가 허용되지 않는다.
CalNumber = Number;
for (int i = 0; i < NumberCount; i++) {
int Value = CalNumber / power;
_Ptr[i] = Value + '0';
CalNumber -= Value * power;
power /= 10;
}
}