주식회사 누리아이티

정보자산의 보안강화를 위한 다계층 인증SW (BaroPAM) 전문기업.

▶ Tuxedo/C

프로그래밍시 추천사항

누리아이티 2010. 6. 28. 21:50

- 변수와 데이터 구조
  C,C++에서 변수가 메모리에 머무는 기간, 스코프, 링킹 그리고 관련 있는 오브젝트등등은 모두 변수를 어디에서 선언했는지에 달려있다. 그러나 메모리에 머무는 기간은 나중에 storage class specifier로 다시 선언하면 바꿀 수 있다. 가능하면 automatic storage class인 지역 변수(local variable)를 사용하는 편이 좋다.
  지역변수를 사용할 수 없는 경우도 있다. 같은 파일내의 서로 다른 두 함수가 데이터를 공유하려면 정적 변수(static variable)같이 정적으로 저장되는 종류의 변수를 사용해야 한다. 이러한 변수나 오브젝트는 내부적으로 링킹이 완료되어야 하는데, 즉 컴파일 단위 안에서만 접근이 가능해야 하고 외부에서 이 변수를 접근할 수 있으면 안 된다. 이러한 경우 컴파일 단위 안에서 정적변수는 지역 변수처럼 취급할 수 있으므로 컴파일러가 좀더 코드를 최적화 시킬 수 있다.
  하나 이상의 컴파일 단위끼리 정보를 공유하려면 외부 변수(external variable)를 사용해야 하는데 이 경우 불필요하게 메모리에 접근하는 것을 피하기 위해 필요한 변수를 구조체로 모아놓는 편이 좋다.

 

- 함수
  현재 컴파일하는 코드 안에 함수가 정의되어 있지 않다면 컴파일러는 최악의 상황을 가정하게 된다. 즉 그 함수를 호출하면 역작용(side effect)이 발생할 수도 있으며 이러한 역작용으로 인해 실행환경이 바뀔 수 있다고 가정한다. 다음과 같은 몇 가지 수행으로 역작용이 발생할 수 있다.
  1) 휘발성 변수 및 오브젝트(volatile object)를 참조할 때
  2) 외부 변수 및 오브젝트(external object)를 참조할 때
  3) 정적 변수 및 오브젝트(static object)를 참조할 때
  4) 파일을 수정할 때
  5) 위의 동작을 수행하는 함수를 호출했을 때

  만약 함수에 입력을 해야 한다면, 함수가 직접 전역 변수를 참조해서 값을 읽어가는 것보다 입력값을 인자 (argument)로 넘겨주는 편이 좋다.
  만약 함수에 아무 역작용도 없다면 - 즉 위의 사항에 해당되지 않는다면 - #pragma isolated_call 디렉티브를 사용해서 컴파일러가 좀더 최적화를 잘 할 수 있도록 도와줄 수 있다. 이 경우 실행시간이 줄어드는 성능 향상을 보장할 수 있다.
  만약 현재 컴파일하는 단위 안에서만 함수가 필요한 경우라면, 이 함수를 static 으로 선언하면 속도가 좀더 빨라진다.
  C++에서 반드시 필요한 경우가 아니라면 가상 함수(virtual function)를 사용하지 않는 편이 좋다. 실제로 수행되기 이전에는 가상함수의 위치가 정해지지 않기 때문이다. 컴파일러는 가상함수를 호출하기 위해 가상함수 테이블의 엔트리에 대해 간접적인 호출을 하도록 코드를 생성하고 이 경우 가상함수의 실제 위치는 로드할 때가 되어야 할 수 있다. 코드 분량을 줄이려면, 가상함수를 인라인으로 선언하면 안 된다. 가상함수를 인라인으로 선언하면 가상함수를 사용하는 클래스 때문에 생성해야 하는 가상함수 테이블이 훨씬 커지기 때문이다.

 

- 포인터
  일단 포인터를 사용하게 되면 데이터 흐름상 불확실성이 생길 수 밖에 없으며, 컴파일러가 마음 놓고 최적화를 수행할 수 없다. 변수의 주소에 대해 포인터를 할당하게 되면, 포인터와 변수 두개의 경로로 같은 메모리 주소를 참조할 수 있게 된다.
  포인터가 어느 부분을 가리키는지 컴파일러가 전혀 알 수 없다면, 컴파일러는 여기에 대해 가장 보수적으로 가정을 해서 포인터가 어떤 변수든 가리킬 수 있는 것으로 가정한다.
  #pragma disjoint 디렉티브로 변수의 물리적 메모리 공간이 다른 변수와 공유되지 않는다는 사항을 컴파일러에게 알려줌으로써 좀더 강력한 최적화를 수행할 수 있다. 그러나 실제로는 물리적 메모리 공간을 다른 변수와 공유하는 변수에 대해 이 디렉티브를 사용하게 된다면 프로그램의 결과값이 제대로 나오지 않을 수 있으므로 주의해야 한다.

 

- 숫자 연산
  일반적으로 나눗셈보다 곱셈이 빠르다. 똑같은 숫자로 여러번 나누기를 한다면 나누는 수를 역수로 만들어서 곱셈 연산을 하는 편이 좀더 빠르다.
  total / 1.0825 ==> total * (1.0 / 1.0825)
  나눗셈 연산인 (1.0 / 1.0825)는 컴파일시 단 한번 수행하여 저장되므로 속도가 빨라진다.

 

- 선택구문과 반복구문
  if문을 쓸 때 if의 조건문에서 될 수 있는 대로 앞쪽에 결정이 쉬운 조건을 집어넣어야 한다.
  case문이나 if-else 문을 쓸 때 될 수 있는 대로 발생 가능성이 높은 경우를 조건의 앞쪽에 놓아야 한다.
  for 루프, do 루프, while 루프 등을 사용할 때는 루프문 바깥으로 invariant expression (루프문 내에서 따로 변경이 일어나지 않거나 루프 첨자와 관계없는 표현식)을 빼야 한다.

 

- 표현식
  C/C++ 컴파일러는 다음과 같은 경우 공통된 부표현식(sub-expression)을 찾아낼 수 있다.
  1) 표현식의 왼쪽 끝에 표현식이 있을 때
  2) 괄호 안에 있을 때

  예를 들어, 컴파일러는 다음 두 대입문에서 a + b 부표현식을 찾아낼 수 있다.
  x = a + b + c;
  y = d * (a + b);
  다음 찾아낸 부표현식을 단 한번 계산해서 속도를 높이게 된다. 결국 위의 코드는 논리적으로 다음과 같이 변경된다.
  temp = a + b;
  x = temp + c;
  y = d * temp;
  컴파일러는 부표현식을 계산하여 그 결과를 temp의 역할을 하는 레지스터에 저장한 다음 필요할 때 그 값을 가져다 사용한다.

 

- 메모리 사용
  malloc()이나 calloc()과 같은 메모리를 할당하는 함수를 가지고 작은 오브젝트나 임시로 사용할 오브젝트에 대해 메모리를 너무 자주 할당하게 되면 힙영역에 메모리 단편화 현상(fragmentation)이 심해진다.
  만약 temp의 크기를 미리 알 수 있다면 malloc()을 쓰지 않고, 스택에서 필요한 만큼 영역(char temp[MAX_ELEMENT_SIZE];)을 잡을 수 있다.
  만약 미리 temp의 크기를 알 수 없다면, "가변 배열(Variable length arrays)"을 사용해서 배열의 크기를 동적으로 할당하도록 할 수 있다.

 

- 빌트인함수 (built-in function)
  성능상의 이유로 많은 라이브러리 함수가 컴파일러 빌트인으로 제공된다. 컴파일러 빌트인은 함수를 호출하는 곳에 컴파일러 빌트인의 함수본체를 확장해서 직접 코드를 끼워넣기 때문에 함수호출 시 오버헤드(파라미터를 넘기거나 스택을 할당하는 등)가 없다. 프로그래머가 직접 기계어 명령에 접근할 수 있도록 여러 가지 하드웨어 명령어 빌트인도 제공한다.
  라이브러리 버전의 빌트인 함수를 사용하려면 적절한 라이브러리 헤더 파일을 사용해야 한다. 적절한 라이브러리 헤더파일을 포함해야 파라미터 간에 타입이 맞지 않는 경우를 방지할 수 있고 최적의 성능도 보장할 수 있다.

 

- 가상 함수 (virtual function)
  일반적으로 C++ 코드를 작성할 때 왠만하면 가상 함수(virtual function)를 사용하지 않는 편이 좋다. 보통 가상함수는 간접적인 함수호출로 인코드되기 때문에 직접적 함수호출보다 훨씬 속도가 느리다.
  만약 클래스 안에 인라인된 가상함수가 없다면, 컴파일러는 첫번째 파일에 가상함수 테이블을 만들어서 가상함수 구현에 대한 정보를 제공하게 된다. 그러나 클래스내의 모든 가상함수가 인라인되어 있다면, 클래스를 사용하는 컴파일 단위마다 가상테이블과 가상함수 본체를 계속 복사해 두게 되고 이 경우 각각의 컴파일 단위에서 가상함수 테이블과 함수본체가 내부적으로 링킹이 된다. 이렇게 되면 컴파일시 -qfuncsect 옵션을 사용해도 링커가 실행파일에서 중복된 테이블과 함수본체를 제거할 수 없기 때문에 실행파일의 크기가 커진다.

'▶ Tuxedo > C' 카테고리의 다른 글

코어(Core)가 발생하는 주된 원인  (0) 2010.07.05
DBX 사용예  (0) 2010.07.05
디버깅  (0) 2010.06.25
링크 타임시 에러 점검  (0) 2010.06.25
컴파일시 메시지 분석  (0) 2010.06.25