본문 바로가기
학습/IT

[IT] C언어 입문(14, 끝) C 전처리기(C preprocessor), 함수 포인터(function pointer)

by 개성공장 2021. 9. 18.
반응형

□ C preprocessor, function pointer

 

 * List Creation and Element Counting

 - element를 포인터를 따라가면서 카운팅...

 

recursion 이용

int count(LINK head)
{
	if (head == NULL)
		return 0;
	else
		return (1 + count(head->next));
}

 

 

recursion 이용 안 함

int count(LINK head)
{
	int cnt = 0;

	for(; head!=NULL; head=head->next)   // head=head->next는 head가 다음 element를 포인팅하는 식
	{
		cnt++;
	}
	return cnt;
}

 

---

LINK stringToList(char s[])
{
	LINK head = NULL, tail;
	int i;
	if ( s[0] != '\n' )
		head = malloc(sizeof(ELEMENT));
		head -> d = s[0];
		tail = head;
		for(i=1; s[i] != '\0'; i++) {
			tail -> next = malloc(sizeof(ELEMENT));
			tail = tail -> next;
			tail -> d = s[i]l
		}
		tail->next = NULL;
	}
	return head;
}

---

 

□ C Preprocessor, C 전처리기

 * C Preprocessor (CPP)

 - Lines that begin with a # are called preprocessing directives

 - Communicate with the preprocessor

 - CPP does not know C

 

#include <stdio.h>    // 시스템에서 제공하는 헤더파일
#include "filename"   // 사용자가 만든 헤더파일

 

 * #define

 - #define identifier token_string

 - #define identifier ( identifier, ... ,identifier ) token_string

 - 전부 대분자를 사용하는 것이 관례

 - example

#define PI 3.14159
#define EPS 1.0e-9
#define FOO(x) ( (x) * (x) )  // FOO(i+1) => (i+1)^2, 올바른 형태
#define FOO(x) x*x            // x=i+1 이면 FOO(i+1) => i+1*i+1이 되어 (i+1)^2이 아닌 2i+1이 됨
#define FOO(x) (x)*(x)        // 5 / FOO(k)  => 5 / (k) * (k), 결과가 이상해짐, 식을 사용할 때 괄호에 유의
#define MIN(x,y)  (( (x) < (y) ) ? (x) : (y) )      // x와 y를 비교하여 큰 값을 반환

 * Conditional Compilation

 - #if constant_integral_expression

 - #ifdef identifier   // 정의되어 있는지 참/거짓 판별, 끝에는 #endif 사용

 - #ifndef identifier   : Conditional compilation of the code that follows until #endif is reached  

 - #undef identifier   : Undefine the macro defined by #define

 - defined identifier  =>  defined( identifier )   : operator, 1 if identifier is currently defined, 0 otherwise

 - #if, #ifdef, #ifndef

 - #elif constant_integral_expresion

 - #else

 - #endif

 

 - example

#define DEBUG 1        // 정상적으로 잘 동작하면 값을 0으로 바꿔서 밑의 '#if DEBUG' 동작시키지 않음
...
#if DEBUG
	printf("debug msg\n");	
#endif

---

#define DEBUG

#ifdef DEBUG
	printf("debug msg\n");
#endif

---

 

To prevent the clash of macro names, use #undef

#include "pi.h"    // pi.h 헤더파일 추가
#undef PI          // 헤더파일에 정의되어 있는 PI undefine
#define PI 3.14    // 새롭게 PI define

 

 

 * Predefined Macros

 - 디버깅과 관련, error 발생시 자세한 정황정보(error가 발생한 라인 번호, 시간, 파일이름 등...)

__DATE__  : a string containing the current date

__FILE__ : a string containing the file name

__LINE__ : an integer representing the current line number

__STDC__ : if the implementation follows ANSI C, then the value is a nonzero integer

__TIME__ : a string containing the current time

 

 * assert()

#include <stdio.h>
#include <stdlib.h>
#if defined(NO_DEBUG)
	#define assert(x) ((void) 0)
#else
	#define assert(x)
		if(!(x)) {
			printf("\n%s%s\n%s%s\n%s%d\n", "assertion failed: ", #x, "in file", __FILE__, "at line", __LINE__);
			abort();
		}
	#endif

 

 

 * Operator #

 - # causes stringization of a formal parameter in a macro definition

 - The argument to be surrounded by double quotes

 

#define foo(x, y) \ 
printf(#x " and " #y "\n")

int main(void)
{
	foo( SNU, KOREA );
	return 0;
}

 

 * Operator ##

 - Merges tokens

#define foo(i) x ## i
...
foo(1) = foo(2) = foo(3);
...
/* x1 = x2 = x3; */

 

 * Functions as Arguments

 - Pointers to functions can be passed as arguments, 함수 포인터는 인자로 전달될 수 있음

 - sin, cos 함수 등등 생각해보자

 - example

double sum_square(double f(double x), int m, int n)
{
	int k;
	double sum = 0.0;
		for (k=m; k<=n; ++k)
	sum += f(k) * f(k);
	return sum;
}

 

 

 - 위 예제에서 double sum_square 정의 부분을 아래와 같이 바꿔서 쓸 수 있음

 - double sum_square (double f(double), int m, int n) {  ...  }

 - double sum_square ( double (*f) (double), int m, int n) { ... sum += (*f) (k) * (*f) (k); ... }

 

 * (*f) (k)

 - f : the pointer to a function

 - *f : the function itself

 - (*f)(k) : the call to the function

 - 다양한 표현법이 있음

 

 * Usage

#include <math.h>
#include <stdio.h>
double f(double x);
double sum_square(double f(double x), int m, int n);

int main (void) {
	printf(" %.7f \n %.7f\n ", sum_square(f, 1, 10000), sum_square(sin, 2, 13));
	return 0;
}

double f(double x) {
	return 1.0/x;
}

 

 * 함수 포인터를 배열 형태로 사용하면...

int sub0(void) {printf("sub0()\n");}
int sub1(void) {printf("sub1()\n");}
int sub2(void) {printf("sub2()\n");}

main()
{
	int (*fp[3]) (void);
	int n;

	fp[0] = sub0;
	fp[1] = sub1;
	fp[2] = sub2;
	fp[0]();
	fp[1]();
	fp[2]();

	scanf("%d", &n);
	fp[n]();
}

 

※ C언어 입문 시리즈
1. Introduction - C언어의 역사와 기본 개념
2. Variables - 변수, 대입연산자, 구문규칙, 데이터타입 등
3. Data types, 데이터 타입(자료형)
4. Operators, 연산자 - scanf, 산술연산자, 관계연산자, 증감연산자, 대입연산자, 동등연산자 등
5. Operators, 연산자 - 논리연산자, 단축평가, 대입연산자, if문 및 while문 활용
6. Control flow, 제어흐름 - While문, For문, If문, do-while문 등 루프문
7. Function, 함수 - Goto문, getchar와 putchar, 함수 정의와 프로토타입 선언
8. Scope rules/recursion, 변수의 영역규칙과 재귀호출, 난수생성 예시
9. Array와 Pointers, 배열과 포인터
10. Pointer, 역참조, swap 함수 활용, 배열과 포인터 비교
11. File operation 파일연산, String, 다차원 배열 예시
12. structure, union, enumerated types - 구조체, 공용체, 열거체
13. 자료구조(data structure) 예시 - 연결리스트(linked list)
14. C 전처리기(C preprocessor), 함수 포인터(function pointer)
반응형

댓글