1장 공부 정리.
전처리기 지시자. 포인터 변수 함수 포인터 구조체 <- 목표
1.1 전처리기 지시자
컴파일러로 보내기전 소스코드를 만들고 수정할 수 있도록 하는 과정을 전처리
효과적으로 컴파일전에 코드를 수정하고 변환 할 수 있다는 장점이 있음.
전처리의 목적
전처리 지시자를 제거하고 이를 C 코드로 변환 하는 것
1.1.1 매크로
매크로정의
#define 지시자를 이용해서 정의
각매크로는 이름과 매개변수 리스트를 가진다. 값을 가지고 확장이란 단계를 통해
매크로의 이름으로 대체될 수 있다 .
유사 함수 매크로
#define sum(a,b) a + b
Int main(int ac, char **av) {
int x = 2;
Int y = 3;
Int z = sum(x, y);
}
Int main(int ac, char **av) {
int x = 2;
Int y = 3;
Int z = x + y;
}
로 변경된다.
이때 컴파일러는 이론적으로 매크로에 대해 알지 못함. 따라서
매크로를 함수로 대신 사용하려면 내용을 기억해 둬야 한다.
전처리 단계에서 모른다고 하지만 이미 사실 알고 있는것
#include <stdio.h>
#define PRINT(a) printf(“%d\n”, a);
#define LOOP(v, s, e) for (int v = s; v <=e; v++) {
#define ENDLOOP }
Int main() {
LOOP(counter, 1, 10)
PRINT(counter)
ENDLOOP
return 0;
}
과 같이 전처리 이후 제대로 된 실행을 할 수 있도록 코드를 작성한다.
이를 통해 DSL 을 정의하고 이를 이용해서 코드를 작성하는 활용법 이다.
이를 이용해서 LOOP 를 도는 방법은 반복 명령어를 차례로 몇개의 개별 명령어로 분기 하는것
1000개의 반복이 하나의 매크로가 C에서 1000개의 명령어로 대체 할 수 있다는것
이를 실제 루프로 돌지 않고 개별로 동작하는것을 루프풀기라고 한다. 이는 제한된 환경에서 고성능을 요할때 사용 할 수 있다.
프로젝트가 커지게 되면 이때 사용되는 이진파일의 수는모듈화의 정도와 설계에 들어간 노력에 거의 비례한다고 함.
성능최적화 라는 과정에서 CPU 가 코드 사이를 오가는것이 아니라 선형적으로 순차적으로 계산하도록 함으로
성능의 향상을 꾀하는 방법
1.1.2 조건부 컴파일
조건부 컴파일을 거치면 서로 다른 조건에 기반해 서로다르게 전처리 된 코드 결과를 받게 된다 .
윈도우에서 자주 사용하는
#pragma once 를 이용해서 이중포함을 막기 위해 사용하는 방식이 있음.
허나 코드의 이식성, 이 코드들이 전처리 되어서 여러곳에서 사용되어야 하는 경우에는
사용하지 않는 편이 좋을수 있다.
라고 함.
1.2
포인터 변수는 c 에서 가장 기본적인 개념.
참조와 같이 포인터와 쌍을 이루는 개념으로 대체되었다.
허나 C에서는 포인터가 가르키는 주소를 직접사용 할 수 있다는 특징이
있음.
&연산자는 참조 연산자라고 함.
사용하지 않는 주소는 NULL 을 가르키고 있어야 하며 널을 역참조 할 경우에는 세그먼트가 발생.
포인터의 연산은 배열의 움직임과 유사함. 바이트 배열에서의 움직임과 유사함.
이때 산술연산의 간격은 자료형을 따르게 됨. Int (4), char (1), struct ( struct size)
와 같은 방식으로
Void * 제네릭 포인터
실제 자료형을 알 수 없는 경우 그렇기에 산술 간격을 알 수 없음.
제네릭 함수를 편리하게 정의할 수 있다.
제네릭 함수가 뭘까? <- 반복적으로 선언되는 녀석이라고 생각하면 편할듯함.
타입에 구애받지 않고 동작하는 녀석이다 .
허상 포인터 해제된 포인터, 또는 정의되지 않은 공간에 접근 할때 발생하는 것