관리 메뉴

드럼치는 프로그래머

[C/C++] C 코드 최적화하기 v0.1 본문

★─Programing/☆─C | C++

[C/C++] C 코드 최적화하기 v0.1

드럼치는한동이 2009. 1. 13. 02:22

C 코드 최적화하기 v0.1


ㅁ 문자 배열의 활용

 

특정 값에 대응되는 문자를 변수에 입력하는 코드를 만든다면 다음과 같이 switch 문을 사용할 것이다.
switch ( queue ) {
  case 0 :   letter = 'W';
     break;
  case 1 :   letter = 'S';
     break;
  case 2 :   letter = 'U';
     break;
}

 
이를 다음과 같이 문자의 배열을 인덱스화하면 더 빠른 접근이 가능하고, 사용하기도 쉽다.
static char *classes="WSU";
letter = classes[queue];

  

ㅁ 전역 변수의 사용

 

전역 변수는 절대 레지스터에 할당할 수 없다. 포인터를 사용하여 간접적으로 할당하거나 함수호출을 이용해서 전역변수를 변환할 수 있다. 따라서 컴파일러는 전역변수의 값을 레지스터에 올려서 캐쉬할 수 없게 되고 때문에 글로벌 변수를 이용할 때마다 다시 읽어들이는 오버로드가 생기게 된다. 그러므로 가능하면 글로벌 변수를 직접 호출하는 대신에, 로컬변수를 이용해서 필요한 연산을 하고 그 결과를 글로별 변수에 할당하는 방법을 사용해야 한다.


int f(void);
int g(void);
int h(void);
int errs;

void test1(void)
{
  errs += f();
  errs += g();
  errs += h();
}

void test2(void)
{
  int localerrs = errs;
  localerrs += f();
  localerrs += g();
  localerrs += h();
  errs = localerrs;
}

 

test1은 매번 전역변수를 로드해야 한다. 반면 test2의 경우 레지스터에 등록된 localerrs에 값을 저장하고 마지막에 한번만 전역변수에 접근한다.

  

ㅁ 지역 변수의 사용

 

가능하면 지역변수로 char 이나 short를 사용하지 않도록 한다. char와 short가 사용될 경우 컴파일러는 값을 저장하기 위해서 8bit 혹은 16bit를 할당한 후, 남는 크기를 줄이는 작업을 하게 된다. 이는 24bit, 16bit 만큼을 shift 시키는 연산을 하게 됨을 의미한다. 그러므로 입력되는 데이터가 8 혹은 16 비트라고 하더라도, 32bit로 연산을 하도록 함수를 만들 필요가 있다.

 

int wordinc (int a)
{
   return a + 1;
}

short shortinc (short a)
{
    return a + 1;
}

char charinc (char a)
{
    return a + 1;
}

 

3번째 코드가 가장 빠른결과를 보여줄 것이라고 생각할지도 모르지만, 1번째 코드가 가장 빠르게 작동한다.

 

ㅁ 그외 팁들

 

프로그램을 사용하면 프로그램의 어느 부분이 가장 많은 시간을 소비하는지를 확인할 수 있다. 일반적으로 루프 혹은 third party 라이브러리 함수를 호출하는 영역이 프로그램을 느리게 하는 경우가 많다.

 

사용할 값이 음수가 아니라면 int 형 대신에 unsigned int 형을 사용해야 한다. 어떤 프로세스들은 unsigned integer 연산이 signed 연산보다 매우 빠르다.

 

나누기/나눗셈 작업의 경우에도 음수가 필요 없다면 unsigned 를 명시하는 것이 좋다. signed 값보다는 unsigned 로 나누어질 수 있도록 함수를 조절할 필요가 있다. signed의 경우에는 더 많은 시간이 소비된다. 오른쪽으로 쉬프트 시킬 경우 가장 왼쪽의 비트를 0으로 만들어 주는 연산이 한번 더 들어가기 때문이다.

 

floating point 연산은 매우 느리다. 소숫점 2자리까지의 정확도를 유지하는 회계 프로그램을 만든다면, 모든 값에 x100을해서 int 형으로 바꾼 다음 연산을 하도록 한다.  

가능하면 외부의 수학 라이브러리를 사용하지 않도록 한다. FPUs와 같은 라이브러리는 매우 느리다.

 

나눗셈 연산은 가능하다면 곱셈으로 대체해서 사용하기 바란다. 예를 들어 (a/b) > c 는 b * c가 integer 범위 안이라는 것을 안다면 a > (c * b)로 다시 쓰일 수 있다.


나누기를 할 때 2의 배수를 분자로 함으로써, 코드를 더 효율적으로 만들 수 있다. 이 경우에 컴파일러는 나누기 연산 대신에 shift 연산을 할 수 있기 때문이다. shift 연산은 가장 빠른 연산중의 하나다. 


Comments