void Data::Function() { for(int k = 0; k < 10; ++k) Process(data[k]); for(int k = 0; k < 10; ++k) SendTo(socket, data[k]); } Datum Data::GetData(int slot) { if(slot >= 0 && slot < 10) return Data[slot]; return null; }
void Data::Function() { for(int k = 0; k < 15; ++k) Process(data[k]); for(int k = 0; k < 15; ++k) SendTo(socket, data[k]); } Datum Data::GetData(int slot) { if(slot >= 0 && slot < 15) return Data[slot]; return null; }
와 같이 프로그램 전체를 뒤져 위와 같이 Data[]를 참조하는 부분을 다 고쳐야 합니다. 한군데라도 빠뜨리면 그것이 바로 버그로 나타나게 됩니다.
이럴 경우에 C/C++에서는 #define을 사용할 수 있습니다.
#define DATACOUNT 15
void Data::Function() { for(int k = 0; k < DATACOUNT; ++k) Process(data[k]); for(int k = 0; k < DATACOUNT; ++k) SendTo(socket, data[k]); } Datum Data::GetData(int slot) { if(slot >= 0 && slot < DATACOUNT) return Data[slot]; return null; }
와 같이 한다면 이후에 #define문만 수정하면 됩니다.
#define 기능이 부족한 C#이나 아예 다른 언어일 경우에는 어떻게 할까요? 제 경우에는 저런 상수들만 모아놓는 다른 클래스를 선언합니다.*
public class Constant { public const int DataCount = 10; }
public class Data { public void Function() { for(int k = 0; k < Constant.DataCount; ++k) Process(data[k]); for(int k = 0; k < Constant.DataCount; ++k) SendTo(socket, data[k]); } Datum Data::GetData(int slot) { if(slot >= 0 && slot < Constant.DataCount) return Data[slot]; return null; } }
Constant = { DataCount = 10 } function Function() for k = 1, Constant.DataCount do Process(data[k]); end for k = 1, Constant.DataCount do SendTo(socket, data[k]); end end function GetData(int slot) if(slot >= 0 && slot < Constant.DataCount) return Data[slot]; return null; end
단, Lua처럼 constant기능이 없는 프로그램언어일 경우, 프로그램 실행중 변수값이 바뀌지 않도록 조심해야 합니다.
물론 이렇게 숫자를 그냥 입력하는 것에 비해 상수로 처리하는 것이 더 번거로운 것은 사실입니다. 그냥 간단하게 숫자 두세개 입력하는 것에 비해 #define문을 삽입하고(또는 constant변수를 만들고) 그 변수이름을 입력하는 것이 귀찮을 수도 있습니다.
그 때문에 '여기서만 사용할 것이다', '어차피 바뀌지 않을 값이다' 등 여러 핑계로 숫자를 그대로 입력하고 싶어지는 경우가 많죠(저역시 그런 유혹을 가끔 느끼곤 합니다)
하지만 그런 상황에서도 숫자를 직접 입력하는 것보다 #define/const를 사용하는 것이 좋습니다. 만약
internal class DataClass { private Datum[] = new Datum[100]; internal void Function() { for(int k = 0; k < 10; ++k) Send(socket, Datum[k]); } }
이런 코드가 있다면 어떨까요? Function()의 10이란 숫자가 원래 크기 100을 잘못 쓴 버그라고 생각할 가능성이 큽니다. 하지만
internal class Constant { internal const int DataSize = 100; internal const int FirstElementSend = 10; } internal class DataClass { private Datum[] = new Datum[Constant.DataSize]; internal void Function() { for(int k = 0; k < Constant.FirstElementSend; ++k) Send(socket, Datum[k]); } }
라고 하면 원래부터 앞쪽 일부 데이터만 보내는 것임을 확실히 알 수 있을 것입니다.
* 사실 C/C++에서도 #define을 쓰는 것보다 const 변수를 사용하는 것이 좋습니다. 왜냐하면 #define과 달리 const변수는 디버깅정보로 들어가기 때문입니다.
그때문에 const변수를 사용한다면 디버깅중에 상수값을 확인할 수도, 중간계산값을 확인할 수도 있습니다. #define을 사용하면 디버깅시 최종값만을 확인할 수 있습니다.