compile은 *.c소스를 *.o파일로 변경하는 작업이다. 이때 각 *.c파일에 어떠한 함수가 있다라는 것을 단순 알려주기 위해 *.h파일이 필요하다
단순히 함수가 있다 정도만 알려 주기 때문에 컴파일시 이 *.h파일이 없을 경우에 어떤 함수가 정의 되지 않았다, 찾을 수 없다 등의 에러 메시지를 출력한다.

link의 경우는 이렇게 모인 *.o파일 들을 모아 주는 역할을 한다. 이때에 비로소 어떤 파일에서 사용하는 함수가 어떤 파일에 있다와 같이 참조(reference)하는 부분을 포함하게 된다. 그렇기 때문에 컴파일시 참조 하는 부분을 나타내는 헤더 파일을 include하고 참조하는 library의 위치를 옵션에 넣어줘야 문제 업이 컴파일이 가능하다. 만약 잘못 입려하거나 없을 경우 함수를 참조할 수 없다는 메시지를 출력한다.
library는 -L를 통해 해당 library의 폴더 위치를 넣고 -l를 통해 파일명을 넣어 준다.
-L를 해주지 않아도 컴파일러가 기본으로 찾아가는 순은 /usr/lib -> /lib -> /자기 폴더 순이다.

이렇게 묶인 link파일은 *.a나 *,so파일로 나뉜다. 둘은 목적에 따라 그때그때 다르게 사용한다.

*.a는 static library로서 정적 라이브러리에 해당한다. 정적 라이브러리의 목적은 빠른 접근(속도)에 있다. 하지만 처리속도를 높이기 위해 해당 라이브러리를 참조하는 모든 코드에 매칭되기 때문에 그만큼 용량을 많이 차지하게 된다.(라이브러리 용량이 호출하는 함수의 양만큼 증가) - 미리 빌드
*.so는 dynamic으로서 동적 라이브러리에 해당한다. 동적 라이브러리의 목적은 경량에 있다. 하지만 한번 빌드된 라이브러리의 위치를 각각 빌드시 명시되지 않고 사용시에 호출하여 쓰기 때문에 속도가 정적 라이브러리에 비해 떨어지는 단점이 있다. - runtime시 호출하여 사용
이는 시간과 공간의 반비례 그래프와 같다.


자바개발을 하다 C를 해보려 하니 포인터 개념이 생겨 생각에 정리를 할겸 혼자 되뇌이며 몇자 적어 본다.


int a, b가 있는데 값을 대입하기 위해선 a = b 이렇게 하면된다

그런데 이말인 즉 *&a = *&b 란 뜻이다

&는 주소연산자이며 포인터를 뜻하고 &a하면 int형 변수 a를 가르키는 포인터이다

한마디로 a가 어디있는지 주소를 나타내는 것이다.

*는 참조연산자로서 기억공간을 사용하기 위해 사용되고 &앞에 *& 이렇게 붙이면 당연히 &가 가르키는 주소의 값을 *이걸로 가져다 쓰겠다는 의미이다.


다시 말해서 *&a는 int형 a의 주소에 있는 값을 가져온다는 의미이다.(포인터에 참조연산자를 사용하면 포인터가 가리키는 기억공간의 저장된 값을 사용할 수 있다.)


따라서, a = *&b로도 사용할 수 있다는 말이다.


그렇다면 이러한 &(주소연산자)를 저장할 순없을까?

일반적으로 선언된 int a 와같은 변수에는 값을 저장하는 것이지 주소를 저장할 수는 없다.

하지만 참조 연산자로 변수를 선언하게 되면 이러한 주소 값을 저장할 수 있다.


int *a (포인터변수 선언) 이렇게 말이다.

저장 방법은 int a, *b;  a=10; *b=&a;  이렇게 하면된다.


포인터는 포인터가 가르키는 자료형의 크기와 관계없이 모두 4바이트이다. 따라서 포인터변수의 크기도 모두 4바이트이다.(근데 컴파일러에 따라 달라질 수 있음)

하지만 이렇게 크기가 같다고 해도 형변환이 되는것은 아니다. int형 포인터 변수에 저장된 주소를 double형 포인터 변수에 저장 못함

하지만 강제 형변환은 됨

int *ip;

double db=6.5;

ip = &db; <--하면 에러가 나지만

ip = (int *) &db <-- 이렇게 강제 형변환 하면 문제 없음


정리하자면 포인터는 주소값을 의미함 즉, 상수인 것이고

포인터 변수는 하나의 기억공간이며 번듯한 이름이 있는 변수인 거다.

포인터와 포인터 변수는 모두 특정 기억공간을 가리키는 역할을 하므로 두 가지 모두 참조 연산자를 사용하면 그들이 가리키는 기억 공간을 참조할 수 있다!

그러나 분명한 차이점은 포인터는 상수이므로 가리키는 대상을 결코 바꿀 수 없고, 포인터변수는 다른 주소값을 저장하면 얼마든지 가리키는 대상을 바꿀 수 있다.

int val;
int *ip = &val;    //포인터를 포인터변수에 저장한다
변수 val의 값 : **&ip

& : 주소연산자
val : int형 변수

&val : 포인터
ip : 포인터변수(int *)
&ip : 이중포인터
**&ip : 이중 포인터를 사용하여 변수의 값 참조
* : 참조연산자

이중포인터가 가리키는 것은 포인터변수이므로 참조 연산자를 사용하여 포인터변수에 저장된 포인터 값을 구함

이중포인터 변수
  : 이중 포인터가 가리키는 자료형을 파악한 후에 같은 자료형을 가리키는 포인터변수를 선언하면 됨

이중포인터 &ip는 (int *)형 변수의 포인터이므로 결국 이중포인터가 가리키는 자료형은 (int *)형이 될 것. 따라서 (int *)형을 가리키는 이중포인터변수 선언 가능

예)   
int **ipp;    //int*(가리키는 자료형), *(ipp는 포인터 변수임), ipp(변수의 이름)
int val = 10;    //int형 변수의 선언과 초기화
int *ip;              //포인터변수 선언
int **ipp;         //이중포인터변수 선언
ip = &val;         //int형 변수의 포인터를 포인터변수에 저장
ipp = &ip;         //포인터변수의 포인터를 이중포인터변수에 저장
printf("변수 val의 값 : %d\n", **ipp);    //참조연산자를 두 번 사용하여 참조한다.


1. 배열명을 사용한 배열 표현

   : aa[0];


2. 배열명을 사용한 포인터 표현

   : *(aa+0);


3. 배열명을 저장한 포인터 변수를 사용한 포인터 표현

   : int *ap = aa;     

     ap+0;


4. 배열명을 저장한 포인터 변수를 사용한 배열 표현

   : int *ap = aa;     

     ap[0];


* 배열요소는 참조하는 기본 방식이 포인터 계산에 의한 것이므로 계산 결과가 같다면 표현 형태는 얼마든지 바뀔 수 있음


예) *(ary) == *ary == *(ary+0)

     ary[1] == *(ary+1) == *(1+ary) == 1[ary]

inline 함수는 프로그램의 실행 속도를 높이기 위해서 c++에 추가된 기능이며 쉽게 이해하기 위해 매크로 함수와 비교해 보면 좋다.


예를 들어 아래와 같이 SQUARE라는 매크로를 만들어 사용할 경우,


 
#define SQUARE(x) ((X)*(X))

int main(void)
{
	 std::cout << SQUARE(5) << std::endl;
	 return 0;
}
 


실제 프로그램 실행 시 main 함수의 SQUARE를 사용하게 될 경우 define된 주소로 점프 하여 실행 후 다시 원래로 돌아온다.


하지만 인라인 함수의 경우 전처리이기 아래와 같이 사용 하게 되면, 컴파일 시 인라인 함수가 코드 안에 삽입 되기 때문에 실제 main함수에서 SQUARE를 사용 시 삽인된 코드가 바로 실행 되기 때문에 속도도 빠르고 효율적이다.


 
inline int SQUARE(int x)
{
	 return x*x;
}

int main(void)
{
	 std::cout << SQUARE(5) << std::endl;
	 return 0;
}
 

1. 문자형을 숫자형으로

atoi​,atol,atof는 문자열을 숫자로 바꾸어 주는 함수이다.

사용하기 위해서 stdlib.h 이 헤더를 호출해야 한다.


 
include <stdlib.h>
 


 -. atoi는 ascii to integer --> 문자열을 int형

 -. atol은 ascii to long --> 문자열을 long형

 -. atof는 ascii to float --> 문자열을 double형으로 바꾸어 준다.


​앞에 -가 올 경우도 그대로 출력해 주고 문자나 띄어쓰기를 만나면 그 전까지의 숫자를 모두 바꾸어 준다.

또 시작하자마자 문자를 만날 경우 0을 반환한다.


간단한 예제를 살펴보자!


 
#include 
int main()
{
   char buf1[10], buf2[10];
   int num1, num2;
   
   memset(buf1, 0x00, sizeof(buf1));
   memset(buf2, 0x00, sizeof(buf2));
   
   sprintf(buf1, "20");
   sprintf(buf2, "30");
   num1 = atoi(buf1);
   num2 = atoi(buf2);
   
   printf("num1 + num2 = %d \n", num1+num2);
   
   return 0;
} 
 



2. 숫자형을 문자형으로

 -. itoa : integer 값을 2진, 8진, 10진, 16진 문자열로 변환합니다.

 -. ltoa : long 값을 2진, 8진, 10진, 16진 문자열로 변환합니다.

 -. ultoa : unsigned long 값을 2진, 8진, 10진, 16진 문자열로 변환합니다.

 -. fcvt : 실수(고정 소수점:float) 값을 문자열로 변환합니다.

 -. ecvt : 실수(부동 소수점:double) 값을 문자열로 변환합니다.

 -. gcvt : 실수 값을 부호와 소수점을 포함하여 문자열로 변환합니다.

+ Recent posts