전 처리기 지시문이나 if (constant) 문을 사용하는 것이 더 낫습니까?


10

여러 다른 코스튬 플레이어에 사용되는 코드베이스가 있고 X 유형의 코스튬 플레이어에게만 해당되는 코드가 있다고 가정 해 봅시다. 전 처리기 지시문을 사용하여이 코드를 X 유형의 코스튬에만 포함시키는 것이 더 낫습니까? if 문을 사용합니까? 더 명확하게 :

// some code
#if TYPE_X_COSTUMER  = 1
// do some things
#endif
// rest of the code

또는

if(TYPE_X_COSTUMER) {
    // do some things
}

내가 생각할 수있는 주장은 다음과 같습니다.

  • 전 처리기 지시문은 코드 풋 프린트와 브랜치가 줄어 듭니다 (비 최적화 컴파일러에서)
  • 명령문이 항상 컴파일되는 코드를 생성하는 경우 (예 : 누군가 작업중인 프로젝트의 관련이없는 코드를 손상시키는 실수를 저지르는 경우) 오류가 계속 나타나며 코드베이스를 손상시키지 않습니다. 그렇지 않으면 그는 부패를 인식하지 못할 것입니다.
  • 나는 항상 전 처리기의 사용보다 프로세서의 사용을 선호하라는 말을 들었다.

많은 다른 코스튬 플레이어를위한 코드베이스에 대해 이야기 할 때 바람직한 것은 무엇입니까?


3
최적화 컴파일러를 사용하여 생성되지 않은 빌드를 제공 할 확률은 무엇입니까? 그리고 그것이 발생하면 영향이 중요합니까 (특히 다른 모든 최적화와 관련하여 놓칠 때)?

@delnan-이 코드는 다양한 컴파일러가있는 여러 플랫폼에 사용됩니다. 그리고 영향에 관해서는-특정 경우에 발생할 수 있습니다.
MByD

당신은 무언가를 선호한다고 들었습니까? 마치 닭을 좋아하지 않는 사람이 KFC에서 음식을 먹도록 강요하는 것과 같습니다.
rightfold

@WTP-아니요, 더 알고 싶습니다. 앞으로 더 나은 결정을 내릴 것입니다.
MByD

두 번째 예에서 TYPE_X_CUSTOMER여전히 전 처리기 매크로입니까?
detly

답변:


5

언급하지 않은 #define을 사용하면 한 가지 이점이 있다고 생각합니다. 이는 명령 줄에서 값을 설정할 수 있다는 것입니다 (따라서 1 단계 빌드 스크립트에서 설정).

그 외에는 일반적으로 매크로를 피하는 것이 좋습니다. 그들은 범위를 존중하지 않으며 문제를 일으킬 수 있습니다. 매우 단순한 컴파일러 만 컴파일 타임 상수를 기반으로 조건을 최적화 할 수 없습니다. 이것이 귀하의 제품에 대한 우려인지 모르겠습니다 (예 : 임베디드 플랫폼에서 코드를 작게 유지하는 것이 중요 할 수 있음).


사실, 이것은 이다 임베디드 시스템
MByD

문제는 임베디드 시스템이 일반적으로 gcc 2.95와 같은 고대 컴파일러를 사용한다는 것입니다.
BЈовић

@VJo - GCC는 : 운이 좋은 경우입니다
MByD

그때 사용해보십시오. 사용되지 않은 코드가 포함되어 있고 크기가 크면 정의로 이동하십시오.
Tamás Szelei

컴파일러 명령 줄을 통해 설정하려면 코드 자체에서 상수를 사용하고 해당 상수에 지정된 값만 # 정의하십시오.
코드 InChaos

12

많은 질문에 관해서는,이 질문에 대한 답은 의지에 달려 있습니다. 어느 것이 더 낫다고 말하는 대신 , 하나가 다른 것보다 나은 예제와 목표를 부여했습니다.

전처리 기와 상수 모두 적절한 사용 장소가 있습니다.

전 처리기의 경우 코드는 컴파일 시간 전에 제거됩니다. 따라서 코드가 컴파일되지 않을 것으로 예상되는 상황에 가장 적합합니다 . 이는 모듈 구조, 종속성에 영향을 줄 수 있으며 성능 측면에서 최상의 코드 세그먼트를 선택할 수 있습니다. 다음과 같은 경우에는 전처리기만 사용하여 코드를 나누어야합니다.

  1. 다중 플랫폼 코드 :
    예를 들어, 코드가 다른 플랫폼에서 컴파일 될 때 코드가 특정 버전의 OS (또는 컴파일러 버전)에 종속되는 경우 (매우 드물지만) 예를 들어 little-endien big-endien 코드를 처리 할 때는 상수가 아닌 전처리기로 분리해야합니다. 또는 Windows뿐만 아니라 Linux 용 코드를 컴파일하는 경우 특정 시스템 호출이 매우 다릅니다.

  2. 실험용 패치 :
    또 다른 이유는 정당화되는 것입니다. 위험한 실험용 코드 나 중요한 주요 모듈을 생략해야하는데, 이는 중요한 연결 또는 성능 차이가 있습니다. if () 아래에 숨기지 않고 프리 프로세서를 통해 코드비활성화 하려는 이유 는이 특정 변경 세트로 인해 발생한 버그를 확신 할 수없고 실험적으로 실행되기 때문입니다. 실패하면 다시 작성하는 것보다 프로덕션에서 해당 코드를 비활성화 해야합니다 . 언젠가 는 전체 코드를 주석 처리 하는 데 이상적입니다 .#if 0

  3. 종속성 다루기 :
    생성해야 할 또 다른 이유 예를 들어 JPEG 이미지를 지원하지 않으려는 경우 해당 모듈 / 스텁을 컴파일하지 않으면 라이브러리가 (정적으로 또는 동적으로) 링크되지 않습니다. 구성 단위. 때때로 패키지 ./configure는 이러한 종속성의 가용성을 식별하기 위해 실행 되며 라이브러리가 없거나 (또는 ​​사용자가 활성화하지 않으려는 경우) 해당 기능은 해당 라이브러리와 연결하지 않고 자동으로 비활성화됩니다. 이러한 지시어가 자동으로 생성되면 항상 유리합니다.

  4. 라이센싱 :
    전 처리기 지시문의 흥미로운 예 중 하나는 ffmpeg 입니다. 사용함으로써 특허를 침해 할 가능성이있는 코덱이 있습니다. 소스를 다운로드하고 컴파일하여 설치하면 그러한 것을 원하는지 또는 멀리할지 묻습니다. 조건이 여전히 귀하를 법정에 착륙시킬 수 있는 경우 코드를 숨기십시오 !

  5. 코드 복사-붙여 넣기 :
    일명 매크로. 이것은 매크로를 과도하게 사용하는 것에 대한 조언이 아닙니다. 매크로는 복사하여 과거에 해당하는 것을 훨씬 더 강력하게 적용 할 수 있다는 것 입니다. 그러나주의해서 사용하십시오. 하고있는 일을 알고 있다면 사용하십시오. 물론 상수는 이것을 할 수 없습니다. 그러나 inline쉬운 경우 기능을 사용할 수도 있습니다 .

그래서 언제 상수를 사용합니까?
거의 다른 곳.

  1. 더 깔끔한 코드 흐름 :
    일반적으로 상수를 사용할 때 일반 변수와 거의 구별 할 수 없으므로 코드를 더 잘 읽을 수 있습니다. 75 줄의 루틴을 작성하는 경우 #ifdef가있는 10 줄마다 매우 읽을 수없는 3 줄 또는 4 줄이 있습니다. 아마도 #ifdef에 의해 통제되는 1 차 상수가 주어 졌을 때, 어디서나 자연스럽게 사용할 수 있습니다.

  2. 잘 들여 쓰기 된 코드 : 모든 프리 프로세서 지시문은 잘 들여 쓰기 된 코드 작동하지 않습니다 . 하더라도 당신의 컴파일러가 #def의 들여 쓰기를 허용하지, 사전 ANSI C 프리 프로세서는 라인과 "#"문자의 시작 사이의 공간을 허용하지 않았다; 선행 "#"은 항상 첫 번째 열에 배치해야합니다.

  3. 구성 :
    상수 또는 변수가 의미가있는 또 다른 이유는 전역에 연결되거나 쉽게 구성 파일에서 파생되도록 확장 될 수 있기 때문입니다.

마지막 한 가지 : 전 범위 지시어 나 범위 를 교차하는 데 전 처리기 지시문 을
사용하지 마십시오 . 즉 ,의 다른면에서 시작 또는 끝 . 이것은 매우 나쁘다. 혼란스럽고 언젠가 위험 할 수 있습니다.#ifdef#endif{ ... }#ifdef#endif{ ... }

물론 이것은 완전한 목록은 아니지만 어떤 방법을 사용하는 것이 더 큰 차이를 보여줍니다. 그것은 실제로 어느 것이 더 나은지 에 관한 것이 아니며 , 주어진 맥락에서 사용하기에 더 자연스러운 것입니다.


길고 자세한 답변을 주셔서 감사합니다. 나는 당신이 언급 한 대부분의 것을 알고 있었고 질문은 전 처리기 기능을 전혀 사용할지 여부가 아니라 특정 유형의 사용법에 관한 것이므로 질문에서 생략되었습니다. 그러나 나는 당신이 만든 기본 요점이 사실이라고 생각합니다.
MByD

1
"전 처리기 지시문 #ifdef to #endif를 범위를 넘어서거나 {...} 사용하지 마십시오"는 IDE에 따라 다릅니다. IDE가 비활성 프리 프로세서 블록을 인식하고이를 축소하거나 다른 색상으로 표시하는 경우 혼동되지 않습니다.
Abyx

@Abyx IDE가 도움이 될 수 있습니다. 그러나 사람들이 * nix (linux 등) 플랫폼에서 개발하는 많은 경우에 편집기 등의 선택이 많습니다 (VI, emacs 등). 다른 사람이 당신과 다른 편집기를 사용하고있을 수 있습니다.
Dipan Mehta

4

고객이 코드에 액세스 할 수 있습니까? 그렇다면 전처리 기가 더 나은 옵션 일 수 있습니다. 우리는 비슷한 것을 가지고 있으며 다양한 고객 (또는 고객 특정 기능)에 대해 컴파일 타임 플래그를 사용합니다. 그런 다음 스크립트는 고객 별 코드를 추출하여 해당 코드를 제공합니다. 고객은 다른 고객 또는 다른 고객 특정 기능을 인식하지 못합니다.


3

언급 할만한 몇 가지 추가 사항 :

  1. 컴파일러는 전처리 기가 할 수없는 몇 가지 종류의 상수 표현식을 처리 할 수 ​​있습니다. 예를 들어, 전처리 기는 일반적으로 sizeof()기본이 아닌 유형 을 평가할 방법이 없습니다 . if()경우에 따라 사용이 강제 될 수 있습니다 .

  2. 컴파일러는 건너 뛴 코드 #if(일부 전 처리기 관련 문제는 여전히 문제를 일으킬 수 있음) 에서 대부분의 구문 문제를 무시 하지만으로 건너 뛴 코드의 구문 정확성을 주장합니다 if(). 따라서 일부 빌드에서는 생략되었지만 다른 빌드에서는 생략 된 코드가 파일의 다른 곳 (예 : 이름이 바뀐 식별자)의 변경으로 인해 유효하지 않은 경우 코드가 비활성화되어 if()있지만 비활성화되어 있지 않은 경우 일반적으로 모든 빌드에서 스 쿼크 됩니다 #if. 코드를 건너 뛰는 이유에 따라 좋은 것이 아닐 수도 있습니다.

  3. 일부 컴파일러는 도달 할 수없는 코드를 생략하지만 다른 컴파일러는 그렇지 않습니다. 그러나 문자열 리터럴을 포함하여 도달 할 수없는 코드 내에서 정적 저장 기간의 선언은 할당 된 공간을 코드로 사용할 수없는 경우에도 공간을 할당 할 수 있습니다.

  4. 매크로는 if()그 안에 테스트 를 사용할 수 있지만 매크로 내에서 전처리 기가 매크로 내에서 조건부 논리를 수행 할 수있는 메커니즘은 전혀 없습니다 [매크로 내에서 사용하는 경우 ? :연산자는 종종 낫지 if만 동일한 원칙이 적용됩니다].

  5. #if지시문은 정의 된 매크로를 제어하는 ​​데 사용할 수 있습니다.

if()컴파일러가 사용하고 있거나 어떤 매크로를 정의해야하는지에 따라 결정을 내리는 경우를 제외하고는 대부분의 경우에 더 깨끗 하다고 생각 합니다. #if그러나 위의 문제 중 일부는 if더 깨끗해 보이는 경우 에도을 사용해야합니다.


1

간단히 말해 : 전 처리기 지시문에 대한 두려움은 기본적으로 2 개, 여러 개 포함 및 읽기 어려운 코드 및보다 비판적인 논리입니다.

프로젝트가 작고 미래에 거의 계획이 없다면, 두 옵션 모두 장단점 사이에서 동일한 비율을 제공한다고 생각하지만 프로젝트가 거대해질 경우 별도의 헤더 파일 작성과 같은 다른 것을 고려하십시오 여전히 전 처리기 지시문을 사용하고 싶지만 이러한 종류의 접근 방식은 일반적으로 코드를 읽기 어렵게 만들고 해당 상수의 이름이 프로그램 자체의 비즈니스 논리에 의미가 있음을 명심하십시오.


이것은 훌륭한 코드 기반이며, 정의는 실제로 별도의 헤더에 있습니다.
MByD
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.