📚 시리즈 목차
2. C언어
2. C언어
1) C 기초
C언어는 데니스 매캘리스터 리치라는 사람이 1972년에 만든 언어이다. (UNIX 운영체제도 만드신 대단한분)
C언어로 코드를 짜면 속도가 빠르고 바이너리 크기도 작아 다른 무엇보다 중요한 임베디드 혹은 모바일 계열, 또는 시스템 프로그래밍 등에서 주로 쓰인다. 과거에는 메모리 가격이 비쌌던 만큼 메모리를 적게 잡아먹는 프로그래밍 기법을 선호했으며, 화성 탐사선도 이러한 점을 반영하여 C언어로 만든 프로그램을 사용했다.
이렇게 C는 아주 오래되고 전통적인 순수 텍스트 기반의 언어이다.
자 그럼 어떤 언어이든 "hello, world" 출력하는 것으로 시작하는데 C언어는 어떻게 하는지 알아보자
(1) int main(void)
일단은 int main(void) 이 부분부터 보자
C언어에서 'int main(void)' 함수는 프로그램의 시작점을 나타내는 특별한 함수이다.
모든 C프로그램은 실행될 때 'main' 함수부터 시작하게 된다.
따라서 'main' 함수는 C프로그램에서 반드시 필요한 함수이다.
한 마디로 프로그램의 시작점이라고 생각하면 편하다.
그렇다면 앞에 int는 무엇일까?
이것은 해당함수의 return 값이 어떤 타입을 반환하는지 나타내는 기호인데 잘 보면 위 예제는 return 값이 없어서 'void'가 되어야 하는 거 아니야?
할 수 있지만 C언어에서는 main 함수가 어떤 값을 반환하지 않고 함수를 종료하는 경우도 허용한다. 이는 C언어의 특수한 규칙 중 하나이다. 위 예제처럼 아무것도 return 하지 않는다면 컴파일러에 의해 'return 0;이 추가되어 안전하게 함수가 안전하게 종료된다.
만약 int 타입이 아닌 다른 것을 반환하고자 한다면 변경해줘야 한다. ( 실수값을 return 하고 싶다면 'float main(void)')
(2) printf
c언어에서 JS console.log() 함수역할을 하는 것은 printf이다.
이 함수 안에 문장을 적을 때는 반드시 " " 큰따옴표로 감싸야한다.
(3) 세미콜론(;)
C언어에서는 JS와 다르게 자동으로 ;을 알아서 넣고 코드를 실행하지 않는다.
항상 문장 코드 끝은 세미콜론으로 끝나야 한다. ( 단, 반복문, 조건문, 함수등은 예외다)
(4) #include <stdio.h>
#include <stdio.h>는 "stdio.h"라는 이름의 파일을 찾아서 "printf" 함수에 접근할 수 있도록 해준다.
끝으로 c언어로 작성한 코드의 파일은 "파일이름.c"로 저장해야 한다.
컴파일러
우리가 직접 작성한 코드는 "소스 코드"라고 부른다.
이를 2진수로 작성된 "머신 코드"로 변환해야 컴퓨터가 이해할 수 있다.
이런 작업을 컴파일러라는 프로그램이 수행해준다.
(소스코드에서 컴파일한다고 바로 머신 코드가 되지는 않는다)
이 과정은 더 세밀하게 나눠져 있다.
일반적으로 C나 C++와 같은 언어의 컴파일 과정은 전처리 -> 컴파일 -> 어셈블 -> 링크로 나누어져있다.
전처리 단계에서는 소스 코드 파일에 포함된 전처리 지시문들을 처리하여 소스 코드의 수정이 이루어진다. 이 단계에서는 주로 "#include"를 사용하여 헤더 파일을 포함하거나 매크로를 정의하고 확장하는 등의 작업이 이루어진다. 전처리 단계를 마치면, 전처리된 소스 코드가 생성된다.
컴파일 단계에서는 전처리된 소스 코드가 컴파일러에 의해 분석되고 기계어로 변환된다. 컴파일러는 소스코드를 문법에 맞게 분석하여 중간 형태의 오브젝트 코드를 생성한다. 오브젝트 코드에는 기계어 명령어, 데이터, 심볼 데이블 등의 정보가 포함된다.
어셈블 단계에서 오브젝트코드는 기계어로 변환된다. 어셈블러는 오브젝트 코드를 기계어로 변환하여 기계어 명령어와 데이터로 이루어진 바이너리 형태의 코드를 생성한다. 이 단계에서는 심볼들이 아직 주소로 해결되지 않은 상태이다.
마지막으로, 링크 단계에서 오브젝트 코드들이 연결되어 최종적인 실행 파일인 머신 코드가 생성된다. 링커는 오브젝트 코드들을 하나로 합치고, 심볼들을 해결하여 실행 파일로 만든다. 링크 단계를 통해 주소 해결, 외부 라이브러리와의 연결, 코드의 배치 등이 이루어진다.
요약하면, 소스 코드는 전처리와 컴파일을 거치면 전처리된 소스 코드와 오브젝트 코드로 변환된다. 어셈블 단계에서 오브젝트 코드는 기계어로 변환되고, 링크 단계에서 오브젝트 코드들이 연결되어 최종적인 머신 코드인 실행 파일이 생성된다.
우리가 위에서 보았던 c코드 파일명이 "hello.c"라고 해보자.
터미널창의 명령어 프롬프트에서 "$"기호 옆에 clang hello.c 라고 입력하면 컴파일이되어 머신코드로 바뀐다.
즉, "clang"이라는 컴파일러로 "hello.c"라는 코드를 컴파일하라는 뜻이다.
이렇게 컴파일하고 나면 a.out이라는 새로운 실행파일이 하나 생성된다.
a.out은 C언어로 작성한 프로그램을 컴파일한 후 생성되는 실행 파일의 기본 이름이다.
실행 파일의 이름을 따로 지정하지 않았을 경우 이이렇게 컴파일러가 자동으로 a.out으로 설정한다.
2) 문자열
get_string 함수는 사용자의 이름을 받는 함수이다.
제일 앞에보면 string 이라고 되어있다.
여기서 유의할 점은 C는 오래된 언어이기 때문에 변수가 저장하는 데이터의 종류를 아주 정확하게 명시해줘야 한다.
그래서 우리는 저장하고자 하는 값의 종류가 문자열(string)이라는 것을 알려줘야 한다.
이때 string을 형식지정자라고 한다.
자 이제 사용자한테 입력을 받았으니 출력을 해보자.
허나 우리가 일반적으로 생각하는 printf("hello answer");이 아니다.
%s 라는 이상한 문자가 들어가있다.
먼저 "%" 는 형식 지정자이다. "%"를 사용하여 출력할 데이터의 형식을 지정할 수 있다.
여기서는 "%s" 이니 string이다. 만약 "%i" 이면 int이다. (단 모든 형식 지정자가 타입의 앞글자를 따서 만든것이 아니니 주의)
이제 이 코드를 컴파일 해보자
이 예제의 파일명은 string.c이다.
<cs50.h> 는 get_string 함수를 담고있는 라이브러리다.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string answer = get_string("What's your name?\n");
printf("hello %s\n", answer);
}
$ clang -o string string.c -lcs50
여기서 -o string 은 string.c를 string.out 이라는 머신코드로 저장하도록 하는 명령어이다.
-lcs50은 "link"라는 의미를 지닌 -l 이라는 인자에 우리가 추가로 포함한 "cs50"파일을 합친것이다.
3) 조건문과 루프
여기 부분은 자바스크립트와 유사해서 쉽다.
#include <stdio.h>
int main(void){
for(int i = 0; i<=9; i++)
{
printf("개발공부는 재미있다.");
}
}
for문과 while문이 동일하다.
4) 자료형, 형식 지정자
(1) 데이터 타입
C에서는 정수나 문자열 외에도 다양한 데이터 타입이 정의되어 있다. 또한 각 타입에 맞는 형식 지정자를 통해 적절한 포맷으로 출력하고, 다양한 연산자를 통해 조건문을 설정하거나 데이터 값을 계산할 수 있다.
- bool: 불리언 표현, (예) True, False, 1, 0, yes, no
- char: 문자 하나 (예) 'a', 'Z', '?'
- string: 문자열
- int: 특정 크기 또는 특정 비트까지의 정수 (예) 5, 28, -3, 0
- long: 더 큰 크기의 정수
- float: 부동소수점을 갖는 실수 (예) 3.14, 0.0, -28.56
- double: 부동소수점을 포함한 더 큰 실수
(2) 형식 지정자
- %d: 10진수 정수를 출력하거나 입력할 때 사용됩니다.
- %f: 부동 소수점 숫자를 출력하거나 입력할 때 사용됩니다.
- %c: 단일 문자를 출력하거나 입력할 때 사용됩니다.
- %s: 문자열을 출력하거나 입력할 때 사용됩니다.
- %x: 16진수 정수를 출력하거나 입력할 때 사용됩니다.
- %o: 8진수 정수를 출력하거나 입력할 때 사용됩니다.
- %u: 부호 없는 10진수 정수를 출력하거나 입력할 때 사용됩니다.
- %e 또는 %E: 부동 소수점 숫자를 지수 표기법으로 출력하거나 입력할 때 사용됩니다.
- %p: 포인터의 주소를 출력할 때 사용됩니다.
- %%: % 기호 자체를 출력할 때 사용됩니다.
예제
# include <cs50.h>
# include <stdio.h>
int main(void)
{
float price = get_float("What's the price?\n");
printf("Your total is %f\n", price*1.0625);
}
float는 실수이니 형식 지정자를 %f로 해서 받는것이다.
여기서 만약 %.2f 로 받는다면 소수점 두 번째자리까지만 받겠다는 것이다.
보충
scanf()
scanf() 함수는 입력 상황에서 사용자 키보드를 검사함으로써 키보드 부터 입력된 데이터를 읽어 들이는 함수이다.
읽어 들인 데이터는 변수에 저장한다.
예제
#include <stdio.h>
main ()
{
int a = 0;
scanf ( "%d", &a);
printf ( "%d", a);
}
scanf()에서 사용가능한 서식 지정자는 printf()와 같으며 입력 받을 값의 자료형에 해당하는 서식 지정자를 큰 따온표 안에 포함시키면 된다. 단, 출력은 하지 않으므로 printf() 처럼 출력 데이터를 첨가하거나, 특수문자를 사용할수 없다.
scanf()를 사용할 때 가장 주의할 점은 값이 입력될 변수의 이름 앞에 참조 연산자 "&"를 붙어야 한다.
"&"연산자는 변수의 메모리 주소를 알려주는 표현으로, 만일 "&"없이 변수 이름만 작성하면 오류가 발생한다.
scanf() 함수의 이름과 내용(의미, 형식)이 사전에 정의되어 있는 라이브러리 함수로 프로그램에 헤더 파일이 없으면 오류가 발생한다.
문제 복습
형식 지정자
%f : 실수를 출력할 때 사용한다. %f는 기본적으로 소수점 이하 6자리까지 출력한다.
%.nf 형식으로 사용할 수 있다. 여기서 'n'은 원하는 소수점 이하 자릿수를 나타낸다.
ex) printf ("%.2f , 3.14159); 는 3.14를 출력한다.
%s : 문자열을 출력할 때 사용한다.
%i or %d: 정수를 출력할 때 사용한다. %i 또는 %d는 부호 있는 정수를 출력하는 데 사용된다.
'CS > CS50' 카테고리의 다른 글
[CS50] 1. 컴퓨팅 사고 (1) | 2023.12.31 |
---|---|
[CS50] 6. 자료구조 (0) | 2023.06.17 |
[CS50] 5. 메모리 (1) | 2023.06.01 |
[CS50] 4. 알고리즘 (0) | 2023.05.31 |
[CS50] 3. 배열 (0) | 2023.05.27 |