ETC

좋은 코드 작성 요령

PON_Z 2022. 6. 27. 15:13

1. 간결하게

 

- 예를 들어 정렬되지 않은 정수 배열에 중복 원소가 존재하는지 하는 함수가 있다고 하자

 

bool hasDuplicate(const vector<int>& array) {

 for(int i = 0; i < array.size(); ++i) 

  for(int j = 0; j < i; ++j) 

   if(array[i] == array[j])

     return true;

return false;

}

 

- 매크로를 사용하여 다음과 같이 코드 변경 가능

 

#define FOR(i, n) for(int i = 0; i < (n); ++i)

bool hasDuplicate(const vector<int>& array) {

 FOR(i, array.size())

  FOR(j, i)

     if(array[i] == array[j])

     return true;

return false;

}

 

2. 전역 변수 X

=> 프로그램 흐름 파악 어려움

 

3. 적극적으로 코드 재사용

=> 반복되는 기능이라면 함수나 클래스로 분리해 사용

 

4. 표준 라이브러리 사용

=> queue, stack, algorithm, vector, map 과 같은 표준 라이브러리 적극 활용

 

5. 일관적이고 명료한 명명법 사용

=> bool judge(int y, int x) 보다

bool isInsideCircle(int y, int x) 와 같이 작성

 

6. 코드와 데이터를 분리하기

 

ex)

string getMonthName(int month) {

 if(month == 1) return "January";

 if(month == 2) return "February";

}  ... (X)

 

const string monthName[] = { "January", "February", ... } 와 같이 작성

 

x, y 좌표 이동하는 경우

const int moveX = { 1, 1, -1, -1}

const int moveY = { 1, -1, 1, -1}

와 같이 작성

 

7. 일관된 범위 표현 방식 사용

=> 대부분 반 열린 구간 사용 [a, b) (a <= n < b)

- 위와같이 사용 시 두 구간이 연속해 있는지 확인하기 쉬움

ex) [a, b) , [c, d) 두 구간이 연속해있는지 보려면 b == c 인지 또는 a == d인지만 확인하면 됨

구간의 크기도 b - a로 찾기 쉬움 

 

8. Off-by-one 오류

=> 하나가 모자라거나 하나가 더 많은 경우

ex) 100미터 담장에 10미터 간격으로 울타리 기둥 세우기는

기둥이 10개가 아니라 11개 필요함에 유의

 

9. 오버플로 피해가기

ex) lcm(a, b) = a x b / (gcd(a, b) 이다.

코드로 옮기면

 

ex)

int gdc(int a, int b);

int lcm(int a , int b ) {

 return (a * b) / gcd(a , b);

}

 

인데 a, b가 50000, 100000 일 경우 인간은 답을 구하기 쉽지만,

만약 a, b 가 int 형일 경우 32비트를 넘어 오류가 난다.

 

그러니 해당 수식에서 a와 b중 하나를 64비트 정수형으로 캐스팅 해주거나

ex)

int lcm(int a , int b ) {

 return (a * (long long) b) / gcd(a , b);

}

 

곱셈 순서를 바꿔보자. b는 gcd(a, b)로 무조건 나누어 지므로 b / gcd(a, b)연산을 먼저 하면

비트수로 인한 오버플로우를 막을 수 있다.

ex) 

int lcm(int a , int b ) {

 return (a  *  (b  / gcd(a , b);

}

 

10. 자료형의 프로모션

=> 사칙연산, 비교 등은 보통 두 개의 피연산자를 받는데

만약 피연산자들의 자료형이다르거나 자료형의 범위가 너무 작은 경우,

컴파일러가 이들을 같은 자료형으로 변환하여 계산한다.

이를 프로모션이라고 한다.

 

ex)

bool isSorted(const vector<int>& seq) {

 for(int i = 0; i < seq.size()-1; ++i) 

  if(seq[i] > seq[i+1])

  return false;

return true;

}

위의 코드인 경우 문제가 없어 보이지만 seq.size()는 unsigned int(size_t)를 반환한다.

프로모션 규칙에 의해 seq.size()-1이 size_t로 강제 변환되면

2^32 - 1 값으로 자동 변환 되기 때문에 에러가 발생한다.

 

이를 막기 위해 seq[]가 비어있는 경우를 처음에 예외처리 해주거나,

seq.size()를 int 형으로 변환하거나

i를 1부터 시작하도록 바꿔야 한다.

728x90

'ETC' 카테고리의 다른 글

화면보호기 방지  (0) 2024.04.26
Smilegate Unsmile AI 사용법  (0) 2023.05.08
유용한 VSCode Extension 및 hot key  (0) 2022.07.08
코드 최적화 팁 [c++]  (0) 2022.06.29