본문 바로가기
코스웨어/10년 스마트폰BSP

[BSP]업무일지 -김강수 - 20100611

by 알 수 없는 사용자 2010. 6. 13.
728x90
반응형

※코드는 더보기를 클릭해주세요※

인라인 함수

인라인 함수의 기본 개념은 함수를 호출하는 대신에 함수의 내용을 그대로 옮겨 놓은 것이다.







일반적인 함수와는 다르게  인라인함수는 다음과 같이 인식하게 된다






보다시피 함수 Func()의 내용을 고스란히 옮겨놓았다.

일반적인 함수는

메인함수 - 호출 -내용 - 값 반환  - 메인함수 : 처럼 넘어갔다가 돌아오는 작업이나

 인자를 복사하는 과정에서 많은 부하가 발생한다.

인라인 함수를 사용하면 이런 작업들을 거치지 않아 시간을 줄일 수 있다.

하지만 인라인 함수는 프로그램의 크기가 커진다는 단점이 있다.
메인함수에서 인라인 함수를 호출하는 곳이 많으면 많을 수록 크기는 더욱 커져서

오히려 속도가 떨어질 수도 있는 상황이 생긴다.


인라인 함수의 가이드라인

- 함수의 내용이 몇 줄 정도로 짧은 경우에만 인라인 함수로 만들자.

하지만 인라인 함수로 만들고 싶어도 항상 되는 것이 아니다.
안 될 경우에는 일반적인 함수로 된다.

멤버 함수를 인라인 함수를 만드는 법

- 클래스의 내부에 정의한 멤버 함수들은 모두 자동으로 인라인 함수가 된다.
- 클래스의 외부에 정의한 멤버 함수는 함수의 정의 앞에 inline  키워드를 추가한다.


어찌보면 C 의 #define 과 비슷하다






하지만 인라인 함수는 인자에 Data type 을 지정할 수 있다.

그리고 #define 은 전처리 과정
인라인 함수는 컴파일 과정에서 처리된다.


변수가 저장되는 모습을 보자









1. 초기화 하지 않은 전역변수 - BSS영역(A,C)
2. 초기화 한 전역변수 - DATA  영역(B,C)

3. 초기화 하지 않았다가 값을 넣은 지역변수 -DATA 영역(E)

5. BSS영역의 전역변수의 값 = 0
6.  지역변수의 메모리 주소를 보면

먼저 선언한 &F = 12ff7c
후에 선언한 &G= 12ff78
뒤에 선언한 변수의 주소가 4바이트(int) 작아졌다.

7. DATA영역과  BSS영역에 있는 (A,C) 와 (B,D,E)의 주소를 보면
후에 선언한 것의 값이 4바이트(int)씩  커진다.

8. DATA, BSS 영역과  STACK 영역에서 주소를 할당하는 방법이 다르다는 것을 알 수 있다.


main 함수도 인자를 받는다

지금까지는 인자를 전달받지 않게 void로 선언되었다.
하지만 프로그램 실행 시 인자를 전달받을 수 있도록 main함수를 선언하는 것도 가능하며 인자를 전달하는 것도 가능하다.







 int main(int A, char *pA[])

A는 임의로 정한 변수 명이고, pA역시 임의로 정한 배열의 이름이다.

첫번째 인자로 전달되는 것은 문자열의 개수다.
int A = 4;가 되겠다.

두번째 인자로 전달되는 것은 문자열을 담을 char형 포인터 배열을 형성한다.
char *pA[3]; 가 되겠다.  (배열의 길이가 4이므로 []안은 3이된다. ) 

공백을 기준으로 문자열을 형성한다.



위와 같지만 약간 다른 코드를 보자







우선 코드를 보면 main 함수에서 두번째 인자를 보면

char *pA[] == char **pA 이 됨을 알 수 있다.

그리고  실행 할 때 큰 따옴표를 사용하면 공백을 포함한 하나의 문자열로 인식하게 된다.

<예제 1>



인자로 문자열을 전달하면 해당 문자열을 숫자로 변환해서 리턴해주는 함수 - <stdlib.h>에 선언되어있다.

atoi :  문자열을 int형 데이터로 변환

특징은 결과값을 보고 추론하자.



typedef

typedef(type define) 는 이미 존재하는 자료형에 새로운 이름을 붙이기 위한 용도로 사용된다


  typedef int I_INT;

"기본 자료형 int 를 I_INT로 부를수도 있다." 라는 뜻.

I_INT라는 새로운 이름을 붙여준 다음부터는 원래 int를 통한 변수 선언 뿐 아니라

I_INT라는 새로운 이름을 통한 변수의 선언도 가능해진다.

int A;
I_INT A;

이 두 코드는 동일한 코드이다.
그리고

int *pA;
I_INT *pA;

이 역시 마찬가지이다.

다음 코드를 통해 typedef의 기능을 알아보자.




결과 값은 60이고 지금 그것은 중요하지 않다.

장점을 알아보자
1. unsigned int 를 쭉 적는 것 보다 I_INT 를 쓰는 것이 더 간결해 보인다.
(물론 I_INT가 문자수가 적은 것도 있다.)

2. 만약 I_INT 를 사용하지 않고 unsigned int 로 선언한 변수가 100개가 있다고 치자.

   그런데 unsigned int 를 (signed)int로 바꿔야 하는 상황이 왔다.

   그렇다면 우리는 unsigned int 로 선언한 100개의 변수를 일일이 찾아가서 int 로 바꿔줘야한다.

   하지만 I_INT를 통한 변수선언을 하였다면 일일이 찾아가지 않고 
   typedef unsigned int I_INT  만 수정하여 주면 되는 것이다(물론 I_INT는 수정하면 안된다)




구조체란?

하나 이상의 변수를 그룹 지어서 새로운 자료형을 정의하는 것이다.
서로 다른 자료형의 변수, 포인터 변수, 배열도 그룹에 속할 수 있다.

기본적으로 구조체를 정의하는 방법은 이렇다.

 struct str
{
    int name;
    int age;
};

struct : 예약어  str : 태그(tag)라고 부르는 구조체 템플릿의 이름

이 구조체는 기본 자료형 변수를 묶어서 새로운 자료형을 우리 사용자가 직접 정의했기 때문에
사용자 정의 자료형 이라 하고 , 구조체를 이루는 변수(name, age)들을 구조체 멤버(혹은 필드) 라고 한다.
마지막에 중괄호를 닫고 세미콜론으로 끝을 맺는다.


구조체의 선언

(1)
struct BSP
{
    int A;
    int B;
};

int main()
{
 sturct BSP iname;       //변수 iname 의 자료형이 구조체 BSP로 선언되었다.
...
}

(2) 구조체의 원형과 변수의 선언을 동시에 하는 방법

struct BSP
{
    int A;
    int B;
} iname ;

(3) 구조체를 단 하나의 변수로만 사용할 때는 태그없이 선언할 수 있다.
struct
{
    int A;
    int B;
} iname 1;
 struct
{
    int A;
    int B;
} iname 2;

무명이라 서로 다른 타입이 된다.

(4) typedef 을 이용한 방법

typedef struct i_bsp
{
    int A;
    int B;
} BSP ;

int main()
{
     BSP iname1;
     BSP iname2;
...
}

여기서 구조체의 태그인 i_bsp 는 생략될 수 있다. BSP가 자료형으로 정의되며, 일반적으로 많이 사용된다.


구조체의 멤버

구조체의 멤버는 도트연산자(.)를 사용하여 접근한다.

   구조체변수.멤버이름






struct _STD {멤버} STUDENT ;
로 정의하면 

STUDENT st1;
struct _STD st1; 둘 다 쓸 수 있다


구조체와 배열

구조체 배열을 선언하는 방식은 기본 자료형의 배열을 선언하는 방식과 동일하다.

코드를 보자
< 5명의 학생의 정보를 입력받아 info.txt 파일에 기록하는 프로그램>












구조체 배열에서 각 원소의 멤버를 접근할 때는 배열의 색인 뒤에 도트(접근 연산자)를 붙이면 된다.

예를 들어 첫번째 원소의 age에 접근할 때는 다음과 같이 나타낸다.
              
            st[0].age


구조체를 가리키는 포인터 변수

구조체를 가리키는 포인터 변수를 통해서 구조체에 접근할 수 있다.
구조체를 가리키는 포인터변수는 일반 포인터변수와 동일한 방법으로 선언된다.

STUDENT *st;

이 선언으로 포인터 변수 sp는 4바이트의 메모리를 할당받는다.

구조체를 가리키는 포인터변수를 사용하여 구조체에 접근할 때는 도트 표기법 대신 화살표를 이용한다.

예를 들어 구조체의 멤버 age에 접근할 때는 다음과 같이 나타낸다.

        st->age =20;     //(*st).age 와 동일하나 일반적으로 -> 를 쓴다. (마이너스 꺽쇠괄호)



 



다양한 표현법을 알아보았다.



▶ 구조체의 주소

구조체 변수의 주소 값과 구조체 변수의 첫 번째 멤버의 주소 값은 같다.








구조체를 함수의 인자로 전달하는 방법

함수 호출 시 구조체 변수를 인자로 전달하거나 리턴하는 과정에서 일어나는 일은 기본 자료형 변수와 동일하다.

(1) 구조체  멤버를 함수의 인수로 전달하는 경우









(2) 구조체 변수를 함수의 인수로 전달하는 경우





위의 두 방법의 결과를 보면 함수에서 swap한 것은  main문에 영향을 미치지 않는다

바로 Call by Value 에 의한 것이다.

Call by Value에 의한 방식은 값을 전달 할 때 값의 복사가 일어난다.

그래서 많은 멤버를 가지고 있는 구조체의 경우 많은 메모리를 할당해야 하는 단점이 있다.


(3) 구조체의 주소를 인수로 전달하는 방법





 구조체 변수 sm의 주소를 인자로 전달하여, 전달받은 함수 swap에서 값이 조작되면

 sm의 멤버의 값도 조작이 된 것을 볼 수 있다.

 이것은 Call by reference 이다.

 이렇게 하면 구조체의 멤버가 많아도 구조체 포인터형의 변수만 생성하기 때문에 
 4bytes의 크기만 할당하면 된다.




구조체의 저장방식


우선 구조체는 언제 메모리에 할당될까?


1. 구조체를 구성한 뒤
2. 구조체 변수를 선언한 뒤


정답은 2 번이다

구조체는 저번에 언급한대로 사용자 정의 자료형이다.
int, short  이런 것과 마찬가지로 형식만 선언한 것 뿐이기 때문이다.
int 가 메모리에 할당 되지는 않는 것을 생각하면 이해하기 쉽다.

이러한 것을 생각하면 struct 가 예약어라고 불려지는 이유를 알 수 있다.


구조체의 크기는 어떻게 될까?





일단 결과를 보기 전에 계산을 해보자

20바이트(char [20])  + 1바이트 (char) + 2바이트 (short)+ 4바이트(int)= 27 바이트 나오면 되겠다.

결과는?



 예상한 값인 27이 나오지 않았다.

그럼 구조체에서 멤버의 순서만 바꿔보자


#include <stdio.h>
typedef struct
{
 char data[20];
char c_data; 
 int i_data;
 
 short s_data;
 
} EX;
 

우선 결과를 생각해보자. 처음에 28이 나왔으니 역시나 28이 나와야 하지 않을까 .


순서만 바꿨을 뿐인데 32바이트가 되었다.

이것은 우리가 현재 쓰는 32비트 컴퓨터에서 32비트 컴파일러를 사용하였기 때문이다.
32비트 =4바이트로 데이터를 처리하는 것에 가장 최적화 되어있기 때문에
데이터를 4바이트 단위로 저장한다


첫번째 예제의 메모리 할당 모습을 보면




두번째 예제의 메모리 할당 모습은 아래와 같을 것이다.



이처럼 4바이트에 맞춰 저장할려고 하는 것을 막으려면 어떻게 해야할까.

#pragma pack() 이라는 전처리어를 사용하면 된다.


#include <stdio.h>

#pragma pack(1)    
typedef struct
{
 char ex0[20];
 char exc;
 short exs;
  int exi;
 
 
} EX;




#pragma pack(1) 여기서 1은 1바이트 중심으로 저장하겠다는 말이다.

그럼 왜 진작 처음부터 1바이트로 해서 메모리낭비가 없게 하지 라는 생각이 날 것이다.
그것은 아까 언급한것처럼 32비트 cpu에서는 32비트 단위로 데이터를 처리하는 것이 가장 빠르기 때문이다

#pragma pack(1)로 선언하고 원래대로 돌려놓지 않으면 속도저하의 문제가 생길 수 있다.

따라서 위의 구조체 끝나는 부분에 #pragma pack(4)라고 선언해 주어야 할 것이다.

여기서도 문제가 있다.
만약 32비트의 cpu가 아닌 8~16 비트체제에서는 어떻게 해야할까.
일일이  찾아서 cpu에 맞게 고쳐주고 다시 컴파일 해야하는 불편함과 어려움이 생길 것이다.

그래서 다음과 같이 쓰면 되겠다

#include <stdio.h>

#pragma pack(push,1)    
typedef struct
{
    char data[20];
    char c_data;
    short s_dat;
    int i_dat;
 
} EX;
#pragma pack(pop)

기존의 바이트를 stack에 push 하고 1바이트로 처리한 다음
끝나는 부분에 원래의 바이트 단위를 pop 해주는 코드이다.



마지막 <구조체의 크기 >부분의 출처
출처 : http://lsea.tistory.com/220







728x90