모각코

[2025 하계 모각코] 2회차 활동 결과 - C언어 표준과 전처리기(선행처리기)

pengine 2025. 7. 15. 23:13

활동 목표: C언어 표준 문법과 함수 및 라이브러리 학습

 

활동 결과

 

1. C언어 표준 문법

 

표준 문법이라고 표기를 해두었는데 사실은 코딩 규칙에 관한 것을 학습하고 싶었다.

함수나 변수 명명법이나 들여쓰기 등에 관한 규칙 말이다.

언어마다 각 언어에 맞는 스타일대로 코드를 작성하는 것 또한 중요하기 때문이다.

 

- 작성법

프로그램의 시작은 main 함수를 호출하여 시작한다.

블록 구조({}) 를 사용하며 문장 단위로 세미콜론(;)을 사용하여 끝맺는다.

 

 

- 명명법

영문자와 숫자의 조합으로 만든다.

명칭의 첫 문자는 문자나 언더바(_)여야 한다.

특수문자를 사용하면 안 된다.(단, 언더바(_)는 사용 가능)

문자 사이에 공백이 있으면 안 된다.

예약어를 사용하면 안 된다.

영문자 대문자와 소문자는 구분되어 사용된다.

명칭의 길이는 컴파일러에 따라 제한이 있다. (일반적으로 32자까지 가능)

 

변수: 모두 소문자로 적으며 단어 사이에 언더바(_)를 적는다.

전역변수: g_와 같이 구분할 수 있는 접두어를 붙인다.

상수 이름: k라는 접두어를 붙여 구분할 수 있고 매 단어의 첫 번째 글자를 대문자로 적는다.

함수 이름: 대문자로 시작하고 매 단어의 첫 번째 글자를 대문자로 적으며 언더바(_)를 사용하지 않는다.

매크로 이름: 대문자와 언더바만 사용한다

 

- 주석 

한 줄 주석: //

여러 줄 주석 /* */

 

2. 함수 및 라이브러리

 

여기에서도 라이브러리라고 명칭을 하였는데 실제로 궁금했던 내용은 전처리기 혹은 선행처리기에 대한 내용이었다. 물론 이는 비슷한 내용이기 때문에 라이브러리를 설명하기 위해 전처리기 혹은 선행처리기에 대해 설명해야 한다.

 

-전처리기 혹은 선행처리기(preprocessor)

1회차 때 #include <stdio.h>와 헤더 파일에 대해 설명하면서 나왔던 내용에서 조금 더 깊게 들어가보자

#include 구문에서 #으로 시작하고 왜 세미콜론(;)을 사용하지 않을까?

또한 main 함수 안에 있지도 않다. 그러면 프로그램이 실행되지 않는 것 아닐까?

 

#으로 시작하는 이 구문은 전처리기 혹은 선행처리기라고 부르며 컴파일 이전에 실행되는 것이다.

#include - 파일

#defind - 매크로

#if, #else, #elif, #endif - 조건부 컴파일

 

#include를 통해 헤더파일을 가져올 수 있다. <stdio.h>, <math.h>

 

여기서 의문점이 생길 수 있다. 헤더파일을 가져오는데 헤더파일은 정확히 무엇이고 파이썬에서는 라이브러리를 불러와서 사용하면 됐는데 여기선 왜 헤더파일을 불러오는지.

 

헤더 파일이란 함수의 존재를 컴파일러에게 알리는 역할이다. 1회차 때 #include <stdio.h> 없이 printf 함수를 사용했을 때 printf를 이해하지 못했던 것처럼 헤더파일을 가져오지 못했다면 컴퓨터가 그 함수의 존재를 몰라 컴파일이 되지 않는다.

 

그러면 라이브러리는 어디서 쓰일까?

컴파일이 완료되고 링크 과정에서 라이브러리를 불러온다. 

 

#define을 통해 매크로를 설정할 수 있다.

매크로는 무엇이냐 하면, 변수와 비슷한 느낌이다. 

#include <stdio.h>
#define NAME "홍길동"
#define mul(a, b) (a * b)

int main(){
    printf("%s\n", NAME);
    printf("%d", mul(2, 3));
    return 0;
}

 

어? 그러면 변수는 왜 쓰나요?

변수는 값이 변할 수 있지만 위 매크로는 변하지 않는다.

하지만 C에서는 Python과 달리 상수 선언(const(리터럴))이 존재한다.

그러면 상수는 왜 쓰나요?

하지만 여기서도 구분지은 데에는 이유가 있을 것이다.

 

const에 저장되면 타입을 체크할 수 있고 그 값은 메모리에 할당된다. 또한 디버깅에 용이하다.

하지만 define은 타입을 체크할 수 없고 디버깅이 불가능하다. 하지만 define은 메모리에 저장되지 않아 메모리를 절약할 수 있고 속도가 빠르다.

이유는 define은 전처리기이기 때문에 컴파일 이전에 실행된다는 점에서 이점이 있는 것이다. 하지만 그렇기에 단점도 명확하고 메모리를 아끼는 것 보다 코드의 유지 보수를 중요시하게 생각하는 현대적 입장에서는 const를 주로 사용한다.

 

#if, #elif, #else, #endif 를 통해 조건부 컴파일을 진행할 수 있다.

 

말 그대로 조건에 부합하면 컴파일을 할 수 있다는 의미이다.

#include <stdio.h>
#define VERIFY 1

int main(){
    #if VERIFY
        printf("1번 컴파일");
    #else
        printf("2번 컴파일");
    #endif
}

>> 1번 컴파일

 

 

#endif는 조건부 컴파일 구문이 끝났다는 것을 표시해주는 부분이다.

 

조건부 컴파일은 디버깅, 성능 향상 등 여러 점에서 큰 이점을 제공할 수 있다.

 

void main(), int main() 차이점

앞서 설명하던 것에서 좀 벗어나긴 했지만 함수에 관련한 학습에서 매우 궁금해서 찾아보았다.

여러 코드를 찾아보지만 int main으로 쓰는 사람도 있고 void main으로 쓰는 사람도 있다.

맨 처음에 접한 것은 int main이었다. 이는 return 0;으로 작성되었기 때문에 return값이 0으로 되어있으니까 int로 해두었구나 라고 예상하였다.

 

예상 결과대로 0으로 리턴하므로 int를 사용하는 것이다. return 0;을 쓰지 않더라도 코드 상으로 작동은 하지만 명시적으로 쓰는 것을 권장하는 것이다. 하지만 반환 값이 없는데도 굳이 작성을 해야 하므로 원칙적으로 return 0; 을 작성하지 않는것은 잘못된 코드이다. 따라서 return 0; 을 작성하지 않기 위해 void main이라고 작성하면 되는 것이다.

 

하지만 C언어 표준에서는 main 함수에서 int 0 을 return하라고 명시하고 있다.

표준대로 써야지!