C 부울 매크로에서 단순히 1이 아닌 #define TRUE (1 == 1) 인 이유는 무엇입니까?


160

C에서 정의를 보았습니다.

#define TRUE (1==1)
#define FALSE (!TRUE)

이것이 필요합니까? 단순히 TRUE를 1로 정의하고 FALSE를 0으로 정의하면 어떤 이점이 있습니까?


35
그리고 더 : #define TRUE (’/’/’/’); #define FALSE (’-’-’-’)( coding-guidelines.com/cbook/cbook1_1.pdf 871 페이지 에서 가져옴 )
osgx

2
아니, 그것은 실마리가 없다는 사실에 의한 편집증입니다. C에서 1과 0은 모든 상황에서 동일하게 수행됩니다.
Jens

@osgx 무엇을 의미합니까?
mrgloom

답변:


155

이 방법은 실제 사용 boolean(과 해결 유형 truefalse컴파일러가 지원하는 경우). (특히 C ++)

그러나, C는 ++합니다 (통해 사용 여부를 확인하는 것이 좋습니다 것 __cplusplus매크로) 실제로 사용 true하고 false.

C 컴파일러에서 이것은 0and와 동일합니다 1.
(괄호를 제거하면 작업 순서로 인해 중단됩니다.)


7
그것은 틀 렸습니다. 여기서 bools는 사용되지 않습니다. 의 결과는 1==1입니다 int. ( stackoverflow.com/questions/7687403/… 참조 )
Mat

4
@ 매트 : C ++에서도 boolean유형이 있습니까?
SLaks

9
질문은 C 태그하지만, 실제로 관계 연산자가 반환 ++ C에 truefalse.
Mat

5
@Mat : 나는 이러한 코드는 C ++과 잘 재생하기 위해 C 헤더에 기록 같은데요
SLaks

20
이 C ++로 좋은 플레이하고 싶다면 @SLaks, 그것은 것입니다 #define TRUE true#define FALSE false때마다를 __cplusplus정의한다.
Nikos C.

137

대답은 이식성입니다. 의 숫자 값 TRUE과는 FALSE중요하지 않습니다. 무엇 입니다 중요한 것은 같은 문이 if (1 < 2)평가 if (TRUE)와 같은 문 if (1 > 2)으로 평가 if (FALSE).

C에서, 부여, (1 < 2)평가됩니다에 1(1 > 2)평가됩니다에 0다른 사람이 말했듯이, 그래서, 컴파일러에 관한 한 지금까지 한 실제적인 차이가 없습니다. 그러나 컴파일러 가 자체 규칙에 따라 정의 TRUE하고 정의하게함으로써 FALSE프로그래머에게 그 의미를 명확하게 표시 할 수 있으며 프로그램과 다른 라이브러리 내에서 일관성을 보장 할 수 있습니다 (다른 라이브러리가 C 표준을 따르는 것으로 가정하면 ... 놀랐습니다).


일부 역사
몇 가지 기본 정의 FALSE0TRUE같은 -1. 많은 현대 언어와 마찬가지로, 그들은 0이 아닌 모든 값을로 해석TRUE 했지만로 부울 표현식을 평가 했습니다 -1. 그들의 NOT작업은 1을 추가하고 부호를 뒤집어서 구현되었습니다. 그렇게하는 것이 효율적이기 때문입니다. 그래서 'NOT x'가되었습니다 -(x+1). 이것의 부작용은와 같은 값은로 5평가 TRUE하지만로 NOT 5평가한다는 -6것입니다 TRUE. 이런 종류의 버그를 찾는 것은 재미 있지 않습니다.

모범 사례는
주어진 사실상 제로로 해석 것을 규정 FALSE하고 있는 것처럼 아닌 값이 해석됩니다 TRUE당신이해야 에 부울 보이는 표현을 비교 결코 TRUE또는FALSE . 예 :

if (thisValue == FALSE)  // Don't do this!
if (thatValue == TRUE)   // Or this!
if (otherValue != TRUE)  // Whatever you do, don't do this!

왜? 많은 프로그래머들이 ints를 bools 로 취급하는 지름길을 사용하기 때문에 . 그것들은 동일하지 않지만 컴파일러는 일반적으로 그것을 허용합니다. 예를 들어 글을 쓰는 것은 합법적입니다

if (strcmp(yourString, myString) == TRUE)  // Wrong!!!

그것은 합법적으로 보이며 컴파일러는 행복하게 받아 들일 것입니다. 그러나 아마도 원하는 것을하지 않을 것입니다. 의 반환 값 strcmp()

      만약 0 yourString == myString
    <0 인 경우 yourString < myString
    > 0 인 경우yourString > myString

따라서 위의 줄은 TRUEwhen 만 반환 합니다 yourString > myString.

이 작업을 수행하는 올바른 방법은

// Valid, but still treats int as bool.
if (strcmp(yourString, myString))

또는

// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)

비슷하게:

if (someBoolValue == FALSE)     // Redundant.
if (!someBoolValue)             // Better.
return (x > 0) ? TRUE : FALSE;  // You're fired.
return (x > 0);                 // Simpler, clearer, correct.
if (ptr == NULL)                // Perfect: compares pointers.
if (!ptr)                       // Sleazy, but short and valid.
if (ptr == FALSE)               // Whatisthisidonteven.

프로덕션 코드에서 이러한 "나쁜 예"중 일부를 발견 할 수 있으며 숙련 된 프로그래머가 맹세합니다. 제대로 작동하고 일부는 (대체적으로?) 올바른 대안보다 짧으며 관용구는 거의 보편적으로 인식됩니다. 그러나 "올바른"버전은 효율성이 떨어지지 않으며 이식성이 보장되며 가장 엄격한 정보도 전달할 수 있으며 심지어 새로운 프로그래머도 이해할 수 있습니다.

그만한 가치가 없습니까?


6
(1==1)보다 더 이식성이 없습니다 1. 컴파일러 자체의 규칙은 C 언어의 규칙으로, 평등 및 관계 연산자의 의미에 대해 명확하고 모호하지 않습니다. 컴파일러 가이 물건을 잘못 본 것을 본 적이 없습니다.
키이스 톰슨

1
실제로 반환 된 값 strcmp은 0보다 작거나 같거나 0보다 큰 것으로 알려져 있습니다. -1, 0 또는 1을 보장하지는 않으며 구현 속도를 얻기 위해 해당 값을 반환하지 않는 플랫폼이 있습니다. 그렇다면 strcmp(a, b) == TRUE다음 a > b그러나 반대 의미는 개최하지 않을 수 있습니다.
Maciej Piechotka 1

2
@KeithThompson-아마도 "이동성"이 잘못된 용어 일 것입니다. 그러나 (1 == 1)은 부울 값이라는 사실이 남아 있습니다. 1이 아닙니다.
Adam Liss 2018 년

2
@AdamLiss :에서는 C, (1==1)1타입 모두 일정한 표현이다 int그들은 동일한 의미 값 1로. 나는 그것을 모르는 독자들에게 제공하는 코드를 작성할 수 있다고 생각하지만 어디에서 끝나는가?
키이스 톰슨

2
'not'5는 실제로 비트 레벨에서 -6입니다.
woliveirajr 2016 년

51

(1 == 1)트릭은 TRUEC에 투명한 방식으로 정의하는 데 유용 하지만 C ++에서 더 나은 타이핑을 제공합니다. "Clean C"(C 또는 C ++로 컴파일 됨)라는 방언으로 작성하거나 C 또는 C ++ 프로그래머가 사용할 수있는 API 헤더 파일을 작성하는 경우 동일한 코드를 C 또는 C ++로 해석 할 수 있습니다.

C 변환 단위에서 ; 1 == 1과 정확히 동일한 의미를 갖습니다 1. 와 1 == 0같은 의미 0입니다. 그러나 C ++ 변환 단위에서 1 == 1유형은 bool입니다. 따라서 TRUE매크로는 그런 식으로 C ++에 더 잘 통합됩니다.

더 나은 통합하는 방법의 예는 예를 들어 기능이있는 경우이다 foo에 대한 과부하가 int와에 대한 bool다음, foo(TRUE)선택합니다 bool과부하를. TRUE방금 정의 된 경우 1C ++에서 제대로 작동하지 않습니다. 과부하 foo(TRUE)를 원할 int것입니다.

물론, C99 도입 bool, truefalse이들은 헤더 파일에서 사용할 수있는 C99와 C.와 작업이

하나:

  • 정의의 실천 TRUEFALSE같은 (0==0)(1==0)C99 선행한다.
  • C99를 멀리하고 C90과 함께 작업해야 할 이유는 여전히 있습니다.

당신이 혼합 C 및 C ++ 프로젝트에 노력하고 있으며, C99을 원하지 않는 경우, 소문자를 정의 true, false그리고 bool대신.

#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif

즉, 0==0일부 프로그래머는 어떤 식 으로든 C ++과 상호 운용되지 않는 코드조차도 트릭을 사용했습니다. 그것은 아무것도 사지 않으며 프로그래머가 C에서 부울이 어떻게 작동하는지 오해하고 있음을 시사합니다.


C ++ 설명이 명확하지 않은 경우 테스트 프로그램이 있습니다.

#include <cstdio>

void foo(bool x)
{
   std::puts("bool");  
}

void foo(int x)
{
   std::puts("int");  
}

int main()
{
   foo(1 == 1);
   foo(1);
   return 0;
}

출력 :

bool
int

오버로드 된 C ++ 함수가 혼합 C 및 C ++ 프로그래밍과 어떻게 관련되어 있는지에 대한 의견에서 의문을 제기합니다. 이들은 단지 유형 차이를 보여줍니다. C ++로 컴파일 truebool때 상수를 유지 해야하는 유효한 이유는 완전한 진단입니다. 가장 높은 경고 수준에서 C ++ 컴파일러는 정수를 bool매개 변수 로 전달하면 변환에 대해 경고 할 수 있습니다 . Clean C로 작성하는 한 가지 이유는 코드가 이식성이 높을뿐 아니라 (C 컴파일러뿐만 아니라 C ++ 컴파일러도 이해할 수 있기 때문에) C ++ 컴파일러의 진단 의견을 활용할 수 있기 때문입니다.


3
훌륭하고 과소 평가 된 답변. TRUEC ++ 에서 두 가지 정의 가 다르다는 것은 전혀 분명하지 않습니다 .
user4815162342

4
오버로드 된 함수는 C와 C ++로 컴파일되는 코드와 어떤 관련이 있습니까?
키이스 톰슨

@KeithThompson 오버로딩뿐만 아니라 일반적으로 적절한 타이핑에 관한 것이지, 오버로딩은 플레이 할 때 가장 실용적인 예입니다. 물론 오버로드, 템플릿 및 "C- 호환성"에 대해 제거 된 "복잡한"항목이없는 C ++ 코드 는 실제로 유형에 대해 큰 관심을 갖지는 않지만 주어진 언어에서 개념적 유형 제한을 무시해야한다는 의미는 아닙니다. .
Christian Rau 2016 년

1
@ChristianRau : "실제로 유형에 관심이 없다"는 것은 무엇을 의미합니까? 유형은 C 언어의 핵심입니다. C 프로그램의 모든 표현식, 값 및 객체에는 유형이 잘 정의되어 있습니다. C와 C ++에서 다르게 정의하려는 경우 ( 실제로 C와 C ++로 컴파일되는 코드를 작성해야하는 드문 경우) #ifdef __cplusplus의도를 훨씬 더 명확하게 표현 하는 데 사용할 수 있습니다 .
Keith Thompson

@KeithThompson 예 나는 유형이 얼마나 중요한지 알고 있습니다. 오버로드 및 템플릿과 같은 유형 인식 기능 이 없으면 암시 적으로 서로 (및 C 로 변환 할 수 있기 때문에) 차별화 boolint실제로 중요하지 않습니다. 실제로 "동일한" , 따옴표를주의 )하지만 실제로 두 가지 사이에서 매복 해야 할 상황이 많지 않습니다 . " 템플릿을 사용하는 코드와 오버로드하는 것보다 훨씬 적을" 은 아마도 " 너무 많지" 않았을 것입니다.
Christian Rau 2016 년

18
#define TRUE (1==1)
#define FALSE (!TRUE)

에 해당

#define TRUE  1
#define FALSE 0

C.에서

관계 연산자의 결과는 0또는 1입니다. 1==1로 평가 될 보장 1!(1==1)로 평가 될 보장됩니다 0.

첫 번째 양식을 사용해야 할 이유는 없습니다. 그러나 첫 번째 형식은 거의 모든 컴파일러에서 상수 표현식이 런타임이 아닌 컴파일 타임에 평가되므로 덜 효율적이지 않습니다. 이 규칙에 따라 허용됩니다.

(C99, 6.6p2) "상수 표현식은 런타임이 아닌 변환 중에 평가할 수 있으므로 상수가있는 곳이면 어디에서나 사용할 수 있습니다."

TRUEFALSE매크로에 리터럴을 사용하지 않으면 PC-Lint에서 메시지 (506, 상수 값 부울)를 발행 합니다.

C의 경우 TRUE로 정의해야합니다 1. 그러나 다른 언어는 1 이외의 양을 사용하므로 일부 프로그래머 !0는 안전하게 재생한다고 생각합니다.

또한 C99에서 stdbool.h부울 매크로에 대한 정의 truefalse 직접 리터럴을 사용합니다 :

#define true   1
#define false  0

1
의심의 여지가 있습니다 .TRUE는 모든 사용법에서 1 = 1로 대체되지만 1을 사용하면 1이 대체됩니다. 첫 번째 방법은 추가 비교 오버 헤드가 아니거나 최적화 된 컴파일러로 만들어 졌습니까?
pinkpanther

4
@pinkpanther 상수 표현식은 일반적으로 컴파일 타임에 평가되므로 오버 헤드를 유발하지 않습니다.
ouah

2
1==1로 평가 될 보장1
ouah

3
@ 니코 좋은 질문입니다. 이것은 형식의 코드에 중요하며 if(foo == true), 이는 나쁜 습관에서 플랫 버그로 바뀔 것입니다.
djechlin

1
위험을 지적하는 +1은와 (x == TRUE)다른 진리 값을 가질 수 있습니다 x.
Joshua Taylor

12

C ++ (이미 언급 했음) 외에도 정적 분석 도구가 또 다른 이점입니다. 컴파일러는 비 효율성을 제거하지만 정적 분석기는 자체 추상 유형을 사용하여 비교 결과와 다른 정수 유형을 구별 할 수 있으므로 TRUE는 비교의 결과 여야하며 호환되지 않아야한다는 것을 암시 적으로 알고 있습니다. 정수로.

물론 C는이 호환되는지 말한다,하지만 당신은 도움이 강조 버그에 해당 기능의 의도적 인 사용을 금지하도록 선택할 수 있습니다 - 예를 들어, 누군가가 혼동이있을 수 있습니다 경우 &&&, 또는 그들의 연산자 우선 순위를 실수 한 것.


1
그것은 좋은 지적이며, 아마도 이러한 도구 중 일부 는 노드 의 향상된 유형 정보 덕분 if (boolean_var == TRUE) 에 확장을 통해 바보 같은 코드 를 포착 할 수도 있습니다 . if (boolean_var == (1 == 1))(1 == 1)if (<*> == <boolean_expr>)
Kaz

4

실질적인 차이는 없습니다. 0로 평가 false되고 1로 평가됩니다 true. 당신이 사용하는 것이 사실 부울 식을 ( 1 == 1) 또는 1정의는 true, 어떤 차이가되지 않습니다. 그들은 둘 다 평가int .

C 표준 라이브러리는 부울 정의를위한 특정 헤더를 제공합니다 stdbool.h.


물론 당신은하지 않았지만 ... 어떤 사람들은 특히 음수에 대해 다르게 생각할 수도 있습니다. :)
pinkpanther

뭐? 당신은 그것을 뒤로 가지고 있습니다. true로 평가 1되고 false로 평가됩니다 0. C는 네이티브 부울 유형에 대해 알지 못하며 정수입니다.
djechlin

C에서 관계형 및 항등 연산자 int는 값이 0또는 형식 인 유형의 결과를 생성합니다 1. C에는 실제 부울 유형 ( _Bool,에 bool정의 된 매크로가 <stdbool.h>있지만 C99에만 추가되었으므로 새 유형을 사용하도록 연산자의 의미를 변경 하지 않았습니다)
Keith Thompson

@ djechlin : 1999 표준에 따라 C 에는 기본 부울 유형이 있습니다. 이라고 _Bool하고 <stdbool.h>있습니다 #define bool _Bool.
Keith Thompson

@KeithThompson, 당신은 1 == 1로 평가되는 것에 대해 옳습니다 int. 편집했습니다.
구두

3

우리는 TRUE가 정확한 정확한 값을 알지 못하며 컴파일러는 자체 정의를 가질 수 있습니다. 그래서 당신이 권한을 부여하는 것은 정의를 위해 컴파일러의 내부 컴파일러를 사용하는 것입니다. 프로그래밍 습관이 좋은 경우에는 항상 필요한 것은 아니지만 코딩 스타일이 좋지 않은 경우 문제를 피할 수 있습니다.

if ((a> b) == 참)

TRUE를 수동으로 1로 정의하면 TRUE의 내부 값이 또 다른 값이됩니다.


C에서 >연산자는 항상 1이면 true, 0이면 false입니다. C 컴파일러가 이것을 잘못받을 가능성은 없습니다. 평등 한 스타일 TRUEFALSE스타일의 평등 한 비교 ; 위의 내용은보다 명확하게 씁니다 if (a > b). 그러나 다른 C 컴파일러가 진실과 거짓을 다르게 취급 할 수 있다는 생각은 잘못되었습니다.
Keith Thompson

2
  1. 아이템 목록

일반적으로 C 프로그래밍 언어에서 1은 true로 정의되고 0은 false로 정의됩니다. 따라서 다음을 자주 보는 이유는 무엇입니까?

#define TRUE 1 
#define FALSE 0

그러나 조건문에서 0이 아닌 숫자는 true로 평가됩니다. 따라서 아래를 사용하여

#define TRUE (1==1)
#define FALSE (!TRUE)

사실이 아닌 것과 거짓을 동일하게하여 안전하게 플레이하려고한다는 것을 명시 적으로 보여줄 수 있습니다.


4
나는 그것을 "안전하게 재생"이라고 부르지 않을 것입니다.
dodgethesteamroller 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.