Compiling
make 로 간단히 컴파일 했었는데 사실 컴파일링은 상당히 귀찮은 작업이다.
make 명령어는 clang -o 파일이름 파일이름.c [-라이브러리이름] 라는 긴 명령어를 대신 해준다.
make 명령어 뒤에서는 clang 이 실행되고 있었던 것이다.
#include <stdio.h>
#include <cs50.h>
int main(void)
{
string answer = get_string("what's your name?")
printf("hello, %s", answer);
}
이 프로그램의 이름을 hello 라고 했을 때 컴파일 하려면
clang -o hello hello.c -lcs50 라고 명령어를 입력해야한다. stdio 는 따로 입력 안해도 된다.
컴파일러는 4단계의 동작을 하고 사실 컴파일링은 그 중 한 단계이다.
컴파일링한다는 통상적으로 4단계 동작을 모두 한다는 의미이다.
1. preprocessing (전처리)
int printf(string format, ...);
string get_string(string prompt);
int main(void)
{
string answer = get_string("what's your name?")
printf("hello, %s", answer);
}
전처리를 마친 파일은 이런 형태로 변한다.
#include 로 가져왔던 라이브러리에서 실제로 쓰는 부분이 선언된다.
2. compiling (컴파일링)
컴파일링을 마친 파일은 이렇게 변하는데
여기서 소스코드 에서 어셈블리어 로 변환이 이루어진다.
3. assembling (어셈블링)
어셈블링에서 어셈블리어가 머신코드 (0과 1) 로 변한다.
하지만 참조한 라이브러리도 변환만 했기때문에
0과1로 이루어진 파일 여러개가 합쳐지지 않았다.
4. linking (링킹)
0과1로 이루어진 여러개의 파일을 하나로 통합한다.
Debugging
말그대로 버그를 없애는 과정이다.
실행할때 오류메세지로 실행 자체가 안되고
터미널에서 어디서 오류가 났는지 알려주는 경우도 있지만
실행은 정상적으로 되는데 내가 원하는대로 결과가 안나올 때가 있다.
이럴때 보통 디버깅을 위해 출력(print, printf, console.log ...)을 해본다.
이렇게 터미널에 찍어보는건 빠르지만 난잡한 방법이다.
디버깅 도구가 없거나 시간이 없는 경우 사용할 수 있다.
사실 코딩테스트 같이 시간안에 풀어야하는 경우 사용할 수 있으나
프로그램을 코딩하면서는 지양해야할 부분이다.
출력 대신 디버깅 도구를 사용하는 것이 좋다.
디버깅 도구는 IDE 에 따라 약간씩 달라질 수 있으나 큰 틀은 비슷하다.
특정구간까지 코드를 실행하고 값을 추적할 수 있다.
작고 간단한 문제나 프로그램은 출력을 쓰고
복잡하고 어려운 문제나 프로그램은 디버깅 도구를 쓴다
고 생각하면 디버깅 도구를 쓸 수가 없다!! 이런 생각으로 디버깅 도구를 제대로 쓴 적이 없다.
작던 크던 디버깅 도구가 지원되는 환경에서는 디버깅 도구를 사용해 버릇하는게 나의 목표이다.
Arrays
type 은 bit 의 크기를 정한다.
type 에 따라 주어지는 bit 크기가 달라지는데
*1byte = 8bit
bool = 1byte
int = 4bytes
long = 8bytes
float = 4bytes
double = 8bytes
char = 1byte
string = ?byte (string 길이에 따라 달라짐)
배열은 메모리 덩어리로 볼 수 있다.
만약 int a[3]; 이렇게 쓰면 12bytes 짜리 덩어리를 할당해준다.
그 메모리 덩어리 안에서 4bytes 씩 나눠 쓰는 것이다.
#include <stdio.h>
int main(void)
{
// Scores
int scores[3];
score[0] = 72;
score[1] = 73;
score[2] = 33;
}
scores 라는 int 3 덩어리 배열을 선언하고
index 0 ~ 2 까지 값을 할당하면 다음과 같은 모습이 된다.
여기서 핵심은 3개의 덩어리가 연속적으로 붙어있다는 것이다.
Strings
문자열은 사실 문자의 배열이다.
char 가 연속적으로 붙어있는 모양을 띈다.
C에서는 "" 를 쓰는 것만으로도 문자열로 인식한다.
위에서 문자열은 할당되는 byte가 문자열의 문자 수에 따라 달라진다고 했는데
컴퓨터는 문자열이 주어졌을 때 어디가 끝인줄 알고 알맞게 메모리를 할당할까?
사실 문자열 타입은 단순히 배열이 아니라 sentinel value 가 포함되어있다.
sentinal value 란 감시값으로 흔히 말하는데
쉽게 말해서 특정한 값에 도달하면 어떤 행동을 취하게 하는 값이다.
C 문자열에서의 감시값은 0byte (이진수 00000000) NUL 널 이라고도 부르는 값이다.
string s = "HI!" 라고 한다면
이런식으로 메모리에 할당되는 것이다.
그래서 문자 3개로 구성된 문자열은 3bytes가 아니라 4bytes가 할당된다.
만약 배열을 통해 문자열을 넣으면 어떻게 될까?
sring words[2];
words[0] = "HI!"
words[1] = "BYE!"
이런식으로 코드를 짠다면 메모리는
이런 형태가 될 것이다.
재밌는 점은 words[0][0] 는 H words[1][0] 는 B 이런식으로 접근할 수 있는데
words[0][4]로 접근하면 가지고 있는 문자를 넘어섰기 때문에 오류가 나야한다.
하지만 배열로 선언된 순간 메모리에 공백이 없는 메모리 덩어리가 되기 때문에
오류가 나는 대신 B에 접근 할 수 있다.
Command-Line Arguments
프로그램을 실행할때 Command Line 에서 매개변수를 받을 수 있는데
습관적으로 입력했던 main 함수를 보면 int main(void)
항상 void 라고 값이 없음을 나타냈다.
(void) 대신에 (int argc, sring argv[]) 를 입력하면 명령어 매개변수를 받고 접근할 수 있다.
argc 는 매개변수의 숫자, argv 는 매개변수를 담고 있는 배열인데
아무런 값을 입력하지 않아도 기본적으로 자기 파일 자체를 담고 있다.
아무것도 입력하지 않아도 argc 는 1이고 argv[0] 은 파일이름이 담겨있다.
명령어 매개변수는 문자열로 들어오고 첫번째 인자는 argv[1]으로 접근해야 한다.
'입문 > CS50X' 카테고리의 다른 글
[CS50X] 2024 Week3 Algorithms (1) | 2024.02.23 |
---|---|
[CS50X] 2024 Week2 Arrays Problem Set 2 (Scrabble, Readability, Substitution) (0) | 2024.02.22 |
[CS50X] 2024 Week1 C Problem Set 1 (Mario, Credit) (0) | 2024.02.21 |
[CS50X] 2024 Week1 C (1) | 2024.02.21 |
[CS50X] 2024 Week0 Scratch (0) | 2024.02.20 |