본문 바로가기

프로그래밍/C language

4. Function and Program Structure

4.1 Basics of Functions

function를 사용하는 것은, 필요 없는 것은 최소화하고 필요한 전체를 볼 수 있게 해 주며 사용성을 높인다.
- function는 argument(인자)와 return을 통해 다른 함수와 communication을 한다. 
- 프로그램은 variable과 function의 집합이다. 
- return문의 문법 : return expr;
- function들은 하나의 source file에 저장될 수도 있고, 여러 source file에 나누어 저장될 수도 있다.
하나의 source file에 저장될 경우, 컴파일 후 하나의 object file이 생기고, 여러 파일에 저장된 경우 
여러 object파일이 생긴다. 여러 object파일들은 load과정에서 하나의 실행파일로 들어가게 된다.
- 아무것도 입력되지 않은 function을 미리 정의해 놓음으로서 앞으로 개발할 function의 공간을
확보해 놓는 것도 유용함

4.2 Functions Returning Non-integers

- return타입이 int형인 곳에 double, float 변수가 return 된다면, 자동으로 int로 변환된다.
하지만, 그것을 명시적으로 casting함으로서 타입 변환을 하는 것이 명시적으로 의도성을 보여줄 수 있다.
- 선언된 function과 정의된 function은 반드시 일관성이 있어야 한다.

4.3 External Variables

- 모든 함수가 사용가능한 외부에서 정의된 변수
- Function의 밖에서 defined 된, argument와 variable들을 뜻하며, 여러 함수가 같은 자원을 공유하고 쓸 때 유용
이를 이용하지 않으면, 매번 argument와 return으로 서로 자원을 공유해야 됨
- Function 그 자체는 항상 external임. 왜냐하면, C에서는 함수 안에서 함수가 정의되지 않기 때문
- 과도한 사용은 function 간에 너무 많은 데이터 연결을 초래하여, 프로그램 구조적으로 좋지 않은 효과를 가져올 수 있음


- ex) 외부 파일의 변수를 사용할 경우, extern int a;

4.4 Scope Rules

- local variable의 경우, function 내부일 경우 scope는 declaration 이후 함수 내부
- external variable/function의 경우, declaration 이후부터 end of file
- file의 외부에서 정의된 변수를 사용하고 싶을 경우, extern을 이용하여 declaration을 해주어야 함
- definition은 저장공간을 할당하지만, declaration은 variable의 property만을 보여준다.

4.5 Header Files

- 프로그램이 여러 file로 나누어진 경우, .h로 시작하는 header file에 function들의 declaration과 공통의 constant expression과 같은
것들을 모아서 centralization 시킬 수 있다. 이렇게 하면, 프로그램이 변경됨에 따라, 올바르게 유지되는
하나의 복사본(header file)만을 갖게 된다. 
- 적당한 크기의 프로그램의 경우, 여러 개로 나누지 않고 하나의 header file에 모든 것을 포함시키는 것이 좋음

4.6 Static Variables 

- ex) static int a = 0; => initialization


- extern variable에 사용할 경우, 다른 file에서 보이지 않음
- Function에 쓰일 경우, 다른 file에서 보이지 않음
- Function내부의 변수에 사용할 경우, 함수가 종료되어도 변수는 저장공간에 값이 유지되며, 함수 밖에서 보이지 않음
따라서, 오직 그 함수만을 위해 지속적으로 쓰일 수 있으며, 초기에 초기화된 값은 다시 함수를 호출하여도 초기화되지 않음.

4.7 Register Variables

- register에 유지되는 variable 따라서, 프로그램의 성능이 향상됨
- function의 parameter 또는 local variable로만 쓰일 수 있음
- register변수의 사용은, 그것의 과도한 사용이나 타입 허용 여부를 알려주지 않음. 따라서, 주의해서 사용해야 함
machine에 따라 사용의 한계가 정해져 있음


- ex) register int x;

4.8 Block Structure

- function내에는 function이 들어갈 수 없으므로, block 구조가 생길 수 없지만 variable은 가능함
- brace(중괄호)를 갖는 블록 구조의 경우, 내부의 variable은 동일한 이름의 외부 variable을 숨김
static을 적용할 경우, block을 나가도 값이 유지됨


- ex) if와 같이 brace(중괄호)가 있는 경우, 중괄호 내 변수의 선언은 statement(또는 block)가 시작됨을 의미함
따라서, 동일한 이름의 block 바깥의 변수를 숨김, brace를 벗어날 때까지만 그 존재를 유지함


int i;
if(...){
   int i;
   static j;
...
}


- 이것은 함수 바깥과 함수 안에서도 적용됨, 동일한 이름의 함수 내부 변수는 바깥 변수를 숨김
- 하지만, 동일하게 안쪽과 바깥쪽 이름을 사용하는 것은 혼란과 실수를 낳을 수 있으니 피하는 것이 좋음

4.9 Initialization

- initializtion을 하지 않을 경우, extern/static variable은 0으로 초기화된다. local/register variable은 정의되지 않은 값이 들어감
- external/static은 constant expression이 되어야 함. 왜냐하면, program의 실행 전에 초기화되기 때문
- local/register의 초기화는, 초기의 assignment(할당)과 동일한 개념임
따라서, constant, expression, function의 return값과 같이 다양한 형태로 초기화 가능
assignment의 개념이므로, declaration과 분리하여 사용하는 것이 가독성 측면에서도 좋음
- array의 초기화의 경우, size를 명시적으로 표시하지 않을 경우, 컴파일러가 숫자를 세서 초기화 시킴
또한, ""를 이용하는 방식으로도 초기화할 수 있음 


ex) int days[] = {31, 28, 31, 30, 31}
char pattern[] = "ould" 은 아래와 동일함
char pattern[] = {'o', 'u', 'l', 'd', '\0'} 

4.10 Recursion

- function이 자기 자신을 호출하는 것을 말한다.
- recirsion은 저장공간을 절약하도록 하지는 않는다. 왜냐하면 진행 중 값의 stack이 유지되어야 하기 때문. 또한, 그렇게 더 빠르지 않을 수도 있다.
- 하지만, recursion은 코드를 compact 하게 표현할 수 있게 해 준다. tree와 같은 recursive 한 date structure에 대해 편리하다.
- recursion은 주로 다음과 같은 문제에서 쓰인다.


if(조건){
변수 저장;
자기 자신 호출;
행위;
}
=> 조건을 만족할 때까지 탐색 후, 조건을 만족하지 않을 경우, '행위'를 recursive 하게 수행함. 
이때, 매 탐색 깊이마다 변숫값을 recursive 하게 저장하여 사용 가능

4.11 The C Preprocessor

- 개념적으로 compilation의 첫 번째 단계임
- 크게, file inclusion, macro substitution, conditional inclusion으로 나뉨

1) File inclusion

- #include <filename> or #include "filename"

-  두 가지의 차이는 해당하는 file을 검색하는 데 차이가 있다.
- <filename>의 검색은 implementation-defined rule을 따르며, 검색 컴파일러/IDE에 의존적이다. 
따라서, 이것은 표준 라이브러리와 같은 헤더 파일을 포함할 때 사용함
- "filename"의 검색은 프로그램이 발견되는 곳에서 검색을 시작한다.(같은 디렉터리 내부)
- 이러한 inclusion은 filename에 해당하는 파일의 contents으로 대체되며, #define문과 extern declaration, function prototype들을 포함시킨다.
- 이러한 inclusion의 사용은, 거대한 프로그램에서 declaration을 함께 묶어주며, source file마다 동일한 정의/변수를 공급받도록 하므로 유용하다.

2) Macro substitution

- #define name replacement_text

- 이후의 동일한 name을 replacement_text로 치환하여 사용한다는 의미, 말 그대로 동일한 텍스트로만 치환하는 것이므로 형식에 구애받지 않음
name부분에 함수 형태로 인자를 전달할 수도 있음 (실제로는 함수 호출이 일어나지 않고 전달된 인자로 치환된 텍스트로 변환)


- ex1) #define forever for(;;) //infinite loop


  ex2) #define sqaure(x) x*x 
  => 주의 : 여기에 만약 z+1을 대입하게 되면, z+1*z+1로 치환되어, 2z+1의 결과가 나온다, 괄호를 써서 전달해야 함.


  ex3) max(i++, j++) 
  => 이러한 경우, increment가 있은 후, 치환 후 또다시 increment가 일어나므로, 총 2번의 increment가 일어나는 side effect가 나타남. 따라서, increment 표현은 쓰지 않는 것이 좋음

- #undef name 은 해당 이름이 이전에 정의되어 있다면 undefined시킴. 주로 이후에 macro가 아닌 function으로 재정의하기 위해 사용
- replacement_text의 #은 인자를 quoted string의 형태로 받겠다는 것을 말함

ex) #define dprintf(expr) printf(#expr " = %g\n", expr)


이것은, printf("expr"" = %g\n", expr)과 동일한 표현이고
두 string을 concatenate시킨, printf("expr = %g\n", expr)과 동일한 표현임

- replacement_text의 ##은 인자를 앞의 인자를 concatenate시킴을 의미


ex) #define paste(front, back) front ## back 
      paste(name, 1) => name1

3) Conditional inclusion

- #if, #elif, #else, #endif문을 통해, constant integer expression들을 비교하여 어떻게 define 하고 include 시킬 것인지 결정할 수 있음

 ex1) #if !defined(HDR)  => #if !defined(HDR)는 #ifndef(HDR)으로 쓸 수도 있음, 이와 반대로는 #ifdef()가 있음
         #define HDR
         #endif

 ex2) #if SYSTEM == SYSV
              #define HDR "sysv.h"
        #elif SYSTEM == BSD
              #define HDR "bsd.h"
        #else 
              #define HDR "default.h"
        #endif
        #include HDR

- 이러한 구조는, 각각의 header가 상호의존성을 다루지 않고, 필요한 header만을 포함할 수 있게 함. 또한, file을 여러 번 포함하게 만드는 것을 피할 수 있음

'프로그래밍 > C language' 카테고리의 다른 글

6. Structures  (0) 2021.08.14
5. Pointer and Arrays  (0) 2021.08.11
3. Control Flow  (0) 2021.03.29
About C language bulletin board  (0) 2021.03.29
2. Types, Operators, and Expressions  (0) 2021.03.29