단락 평가, 나쁜 연습입니까?


88

내가 오랫동안 알고 있지만 결코 고려하지 않은 것은 대부분의 언어에서 순서에 따라 if 문에서 연산자에 우선 순위를 부여 할 수 있다는 것입니다. 나는 종종 null 참조 예외를 방지하는 방법으로 이것을 사용합니다.

if (smartphone != null && smartphone.GetSignal() > 50)
{
   // Do stuff
}

이 경우 코드는 먼저 개체가 null이 아닌지 확인한 다음이 개체를 사용하여 개체가 존재하는지 확인합니다. 이 언어는 첫 번째 문장이 거짓이면 두 번째 문장을 평가해도 아무런 의미가 없으므로 null 참조 예외가 발생하지 않는다는 것을 알고 있기 때문에 언어는 영리합니다. 이것은 andand or연산자 와 동일하게 작동합니다 .

이것은 인덱스가 배열의 경계에 있는지 확인하는 것과 같은 다른 상황에서도 유용 할 수 있으며 이러한 기술은 Java, C #, C ++, Python 및 Matlab과 같은 다양한 언어로 수행 할 수 있습니다.

내 질문은 : 이 종류의 코드는 나쁜 습관의 표현입니까? 이 나쁜 습관은 숨겨진 기술적 인 문제로 인해 발생합니까 (즉, 결국 오류가 발생할 수 있음) 다른 프로그래머에게 가독성 문제를 유발합니까? 혼란 스러울 수 있습니까?


69
기술 용어는 단락 평가 입니다. 이것은 잘 알려진 구현 기술이며, 언어 표준이이를 보장하는 곳에 의존하는 것이 좋습니다. (그렇지 않다면, 언어는 그리 많지 않습니다.)
Kilian Foth

3
대부분의 언어로 원하는 행동을 선택할 수 있습니다. 오퍼레이터 C #의 ||단락, 오퍼레이터 |(단일 파이프)하지 않는 ( &&&같은 동작). 단락 연산자가 훨씬 더 자주 사용되므로 단락이 아닌 연산자의 사용법을 주석으로 표시하여 동작이 필요한 이유 (대부분 발생해야하는 메소드 호출과 같은)를 설명하는 것이 좋습니다.
linac

14
@linac 지금의 오른쪽에 뭔가를 넣어 &또는 |부작용이 발생 확인 나는 확실히 나쁜 관행이다라고 말하고 싶지만 뭔가 만들 : 자신의 라인에 메소드 호출을 넣어 당신에게 아무것도 비용이되지 않습니다.
Jon Hanna

14
@linac : C와 C ++에서, &&단락 &은 아니며, 매우 다른 연산자입니다. &&논리적 인 "and"입니다. &비트 단위 "and"입니다. 것이 가능 x && y진정한 동안이되고 x & yfalse입니다.
Keith Thompson

3
귀하의 구체적인 예는 다른 이유로 나쁜 연습을 할 수 있습니다 : 그것은 어떤 경우 입니다 null이? 여기서 null이되는 것이 합리적입니까? 왜 null입니까? 이 블록 외부 의 나머지 함수 가 널 (null) 인 경우 실행해야합니까, 모든 것이 아무것도하지 않거나 프로그램을 중지해야합니까? 모든 액세스에 대해 "널 (null)"을 문서화하면 (널을 제거하기 위해 서둘러 널 참조 예외로 인해 발생할 수 있음) 전화 개체 초기화가 망친다는 사실을 인식하지 않고 프로그램의 나머지 부분으로 훨씬 멀리 갈 수 있음을 의미합니다. 쪽으로. 그리고 결국, 당신이 마침내 그렇지 않은 약간의 코드에 도달했을 때
Random832

답변:


125

아니요, 이것은 나쁜 습관이 아닙니다. 조건부 단락에 의존하는 것은이 동작을 보장하는 언어 (대부분의 현대 언어 포함)를 사용 하는 한 널리 인정되고 유용한 기술 입니다.

코드 예제는 매우 명확하며 실제로이를 작성하는 가장 좋은 방법입니다. 대안 (예 : 중첩 된 if명령문)은 더 복잡하고 복잡하므로 이해하기 어렵습니다.

몇 가지주의 사항 :

복잡성과 가독성에 대한 상식을 사용하십시오.

다음은 좋은 생각이 아닙니다.

if ((text_string != null && replace(text_string,"$")) || (text_string = get_new_string()) != null)

코드에서 줄을 줄이는 많은 "영리한"방법과 마찬가지로이 기술에 지나치게 의존하면 이해하기 어렵고 오류가 발생하기 쉬운 코드가 생길 수 있습니다.

오류를 처리해야 할 경우 종종 더 좋은 방법이 있습니다

스마트 폰이 null이되는 정상적인 프로그램 상태라면 예제가 좋습니다. 그러나 이것이 오류 인 경우 더 현명한 오류 처리를 통합해야합니다.

동일한 조건의 반복 점검을 피하십시오

Neil이 지적한 것처럼, 여러 조건에서 동일한 변수에 대한 많은 반복 검사는 설계 결함의 증거 일 가능성이 높습니다. smartphoneis null이면 실행하지 말아야 할 10 개의 다른 명령문이 코드에 뿌려진 경우 매번 변수를 확인하는 것보다이를 처리하는 더 좋은 방법이 있는지 고려하십시오.

이것은 실제로 단락에 관한 것이 아닙니다. 반복 코드의 일반적인 문제입니다. 그러나 예제 문장과 같이 반복되는 문장이 많은 코드를 보는 것이 일반적이기 때문에 언급 할 가치가 있습니다.


12
단락 평가에서 인스턴스가 널 (null)인지 점검하는 블록이 반복되면 해당 점검을 한 번만 수행하도록 다시 작성해야합니다.

1
@ 닐, 좋은 지적; 나는 대답을 업데이트했다.

2
내가 추가 할 수있는 유일한 방법은 처리하는 또 다른 선택적 방법을 기록하는 것입니다. 여러 다른 조건에서 무언가를 검사하려는 경우에 선호됩니다 : if ()에서 무언가가 null인지 확인하십시오. return / throw-그렇지 않으면 계속 진행하십시오. 이것은 중첩을 제거하고 종종 "이것은 null이 아니어야하고 만약 그렇다면 여기서 나가야한다"는 것처럼 코드를보다 명확하고 간결하게 만들 수 있습니다. 메소드의 특정 위치에서 특정 조건을 검사하는 무언가를 코딩 할 때는 언제나 좋습니다.
BrianH

1
@ dan1111 "나는 조건이 부작용을 포함해서는 안된다 (위의 변수 할당과 같이)해서는 안된다. 단락 평가는 이것을 바꾸지 않으며, 사이드의 속기로서 사용되어서는 안된다. "if / then 관계를 더 잘 표현하기 위해 if의 본문에 쉽게 배치 될 수있는 효과"
AaronLS

@AaronLS, 나는 "조건에 부작용이 없어야한다"는 주장에 동의하지 않는다. 조건이 불필요하게 혼동되어서는 안되지만 명확한 코드 인 한 조건에서 부작용 (또는 하나 이상의 부작용)에 문제가 없습니다.

26

C 스타일 언어를 사용하지 않고 &&질문에서와 동일한 코드를 수행해야 한다고 가정 해 봅시다 .

코드는 다음과 같습니다.

if(smartphone != null)
{
  if(smartphone.GetSignal() > 50)
  {
    // Do stuff
  }
}

이 패턴은 많이 나타납니다.

이제 가상의 언어 버전 2.0이 소개한다고 상상해보십시오 &&. 당신이 생각했던 얼마나 멋진 생각!

&&위의 예제를 수행하는 인식 된 관용적 수단입니다. 그것을 사용하는 것은 나쁜 습관이 아닙니다. 실제로 위와 같은 경우에는 그것을 사용하지 않는 것이 좋지 않습니다. 그런 언어의 경험이 풍부한 코더 else는 정상적인 방식으로 일을하지 않는 이유가 무엇인지 궁금 할 것입니다.

이 언어는 첫 번째 문장이 거짓이면 두 번째 문장을 평가해도 아무런 의미가 없으므로 null 참조 예외가 발생하지 않는다는 것을 알고 있기 때문에 언어는 영리합니다.

아니, 당신은 첫 번째 문이 거짓이라면 심지어 두 번째 문을 평가 아무 소용이 없다는 것을 알고 있기 때문에, 영리하다. 언어는 바위 상자처럼 바보이며 당신이 말한대로했습니다. (John McCarthy는 훨씬 더 영리했고 단락 평가는 언어가 갖는 유용한 것임을 깨달았습니다).

좋은 습관과 나쁜 습관은 종종 필요한만큼 영리하지만 더 이상 영리하지 않기 때문에 당신이 영리하고 언어가 영리하다는 것의 차이가 중요합니다.

치다:

if(smartphone != null && smartphone.GetSignal() > ((range = (range != null ? range : GetRange()) != null && range.Valid ? range.MinSignal : 50)

이것은 코드를 확장하여를 확인합니다 range. range가 null 인 경우는 호출에 의해 설정하려고 GetRange()하지만 실패 할 range가능성이 있으므로 여전히 null 일 수 있습니다. 이후에 range가 null이 아닌 경우 Valid해당 MinSignal속성이 사용되며, 그렇지 않으면 기본값 50이 사용됩니다.

이것은 &&너무 달려 있지만 한 줄에 넣는 것이 너무 영리합니다 (100 % 확실하지 않으며 그 사실이 내 요점을 입증하기 때문에 다시 확인하지 않을 것입니다).

그것은 &&여기서 문제가 아니지만, 그것을 사용하여 하나의 표현 (많은 것)에 많은 것을 넣을 수있는 능력은 이해하기 어려운 표현을 불필요하게 쓰는 능력 (악한 것)을 증가시킵니다.

또한:

if(smartphone != null && (smartphone.GetSignal() == 2 || smartphone.GetSignal() == 5 || smartphone.GetSignal() == 8 || smartPhone.GetSignal() == 34))
{
  // do something
}

여기 &&에서는 특정 값에 대한 검사와 사용을 결합 합니다. 이것은 전화 신호의 경우 현실적이지 않지만 다른 경우에는 나타납니다. 여기, 내가 영리하지 못한 예입니다. 다음을 수행 한 경우 :

if(smartphone != null)
{
  switch (smartphone.GetSignal())
  {
    case 2: case 5: case 8: case 34:
      // Do something
      break;
  }
}

가독성과 성능이 모두 향상되었을 것입니다 (여러 번의 호출 GetSignal()은 최적화되지 않았을 것임).

여기서 다시 한 번 문제는 &&특정 망치를 들고 손톱으로 다른 모든 것을 보는 것만 큼 중요하지 않습니다 . 사용하지 않는 것보다 더 나은 것을 할 수 있습니다

모범 사례에서 벗어나는 마지막 사례는 다음과 같습니다.

if(a && b)
{
  //do something
}

다음과 비교 :

if(a & b)
{
  //do something
}

우리가 후자를 선호하는 이유에 대한 고전적인 주장은 b우리 a가 진실 인지 아닌지 를 평가 하는 데 부작용이 있다는 것입니다 . 나는 그 부작용이 너무 중요하다면 별도의 코드 줄에서 발생하게하십시오.

그러나 효율성면에서 두 가지 중 하나가 더 좋을 것입니다. 첫 번째 코드는 분명히 적은 코드를 실행하여 ( b한 코드 경로에서 전혀 평가하지 않음) 평가 하는 데 걸리는 시간을 절약 할 수 있습니다 b.

첫 번째는 또한 하나 더 지점이 있습니다. 다음과 같이 가상 C 스타일 언어로 다시 작성하는지 고려하십시오 &&.

if(a)
{
  if(b)
  {
    // Do something
  }
}

그 여분 if은 우리의 사용에 숨겨져 &&있지만 여전히 있습니다. 따라서 분기 예측이 발생하고 따라서 잠재적으로 분기 잘못 예측되는 경우가 있습니다.

이런 이유로 if(a & b)코드가 더 효율적일 수 있습니다.

여기서는 if(a && b)여전히 가장 모범 사례 접근 방식 이라고 말하고 싶습니다 .보다 일반적으로, 경우에 따라 유일하게 실행 가능한 유일한 방법 ( 거짓 b이면 오류가 발생합니다 a)과 그렇지 않은 경우 가 더 빠릅니다. if(a & b)특정 경우에 종종 유용한 최적화 라는 점 은 주목할 가치가 있습니다.


1
성공할 경우 try반환 true되는 메서드가 있다면 어떻게 생각 if (TryThis || TryThat) { success } else { failure }하십니까? 덜 일반적인 관용구이지만 코드 복제 또는 플래그 추가없이 동일한 일을 수행하는 방법을 모르겠습니다. 플래그에 필요한 메모리는 문제가되지 않지만 분석의 관점에서 볼 때 플래그를 추가하면 코드가 두 개의 병렬 유니버스로 효과적으로 분할 true됩니다 false. 때로는 DRY 관점에서 좋지만 icky.
supercat

5
나는 아무것도 잘못 보지 않는다 if(TryThis || TryThat).
Jon Hanna

3
정답입니다.
감독 주

FWIW, Bell Labs의 Kernighan, Plauger & Pike를 포함한 우수한 프로그래머 는 동일한 표현을 두 번 이상 평가하더라도 if {} else if {} else if {} else {}중첩 제어 구조보다는 얕은 제어 구조를 사용하는 것이 더 명확하도록 권장합니다 if { if {} else {} } else {}. Linus Torvalds는 이와 비슷한 말을했습니다. 이것을 단락 작업자에 대한 투표로 보자.
Sam Watkins

if (a && b) 진술; 교체하기가 상당히 쉽습니다. if (a && b && c && d) statement1; 다른 진술 2; 진짜 고통입니다.
gnasher729

10

이것을 더 취할 수 있고, 일부 언어에서는 관용적 인 방법입니다. 조건문 외부에서도 단락 evualuation을 사용할 수 있으며 조건문 자체의 형태가됩니다. 예를 들어 Perl에서 함수가 실패하면 잘못된 것 (성공에는 진실한 것)을 반환하는 것은 관용적입니다.

open($handle, "<", "filename.txt") or die "Couldn't open file!";

관용적입니다. open성공하면 0이 아닌 것을 반환 하지만 die(이후 부분은 or절대 발생하지 않음) 실패하면 정의되지 않은 다음 호출 die이 발생합니다 (즉, Perl이 예외를 발생시키는 방법입니다).

모든 사람이 사용하는 언어로는 괜찮습니다.


17
언어 디자인에 Perl의 가장 큰 공헌은 언어 디자인 을하지 않는 방법에 대한 여러 가지 예를 제공하는 것입니다.
Jack Aidley

@ JackAidley : Perl 's가 그리워 unless지고 postfix 조건부 ( send_mail($address) if defined $address)가 있습니다.
RemcoGerlich

6
@ JackAidley 왜 '또는 죽어'가 나쁜지에 대한 포인터를 제공 할 수 있습니까? 예외를 처리하는 순진한 방법입니까?
bigstones

Perl에서 끔찍한 일을 많이 할 수는 있지만이 예제에서는 문제를 보지 못합니다. 스크립팅 언어의 오류 처리에서 원하는 것, 간단하고 짧으며 명확합니다.

1
@RemcoGerlich Ruby는 그 스타일 중 일부를 물려 받았습니다 :send_mail(address) if address
bonh

6

나는 dan1111의 답변에 일반적으로 동의하지만 , 다루지 않는 특히 중요한 경우가 있습니다 : smartphone동시에 사용되는 경우 . 이 시나리오에서 이러한 종류의 패턴은 잘 찾기 어려운 버그의 원인입니다.

문제는 단락 평가가 원자 적이 지 않다는 것입니다. 스레드가 확인할 수 smartphoneIS null, 다른 스레드에 와서 그것을 무효화 한 다음 스레드는 즉시에 시도 할 수 GetSignal()와 불면.

그러나 물론, 그것은 단지 별 정렬하고 때 스레드 '타이밍이라고하지 단지 권리.

따라서 이러한 종류의 코드는 매우 일반적이고 유용하지만이 불쾌한 버그를 정확하게 방지 할 수 있도록이 경고에 대해 알아야합니다.


3

하나의 조건을 먼저 확인하고 첫 번째 조건이 성공한 경우에만 두 번째 조건을 확인하려는 상황이 많이 있습니다. 때로는 순수하게 효율성을 위해 (첫 번째 이미 실패한 경우 두 번째 조건을 확인하는 지점이 없기 때문에) 때로는 그렇지 않으면 내 프로그램이 충돌하기 때문에 (너무 먼저 NULL 확인) 때로는 그렇지 않으면 결과가 끔찍할 수 있습니다. (IF (문서를 인쇄하고 싶습니다) 및 (문서 인쇄에 실패한 경우)) 그런 다음 오류 메시지가 표시됩니다. 문서를 인쇄하고 싶지 않은 경우 문서를 인쇄하지 않으려는 경우 인쇄가 실패했는지 확인하십시오. 처음!

따라서 논리식의 단락 평가를 보장하는 것이 매우 필요했습니다. Pascal (보증되지 않은 단락 평가를 가진)에는 존재하지 않았으며 이는 큰 고통이었습니다. 나는 먼저 Ada와 C에서 그것을 보았습니다.

이것이 "나쁜 습관"이라고 생각한다면, 약간 복잡한 코드를 취해 단락 평가없이 잘 작동하도록 코드를 다시 작성하여 돌아와서 어떻게 좋아하는지 알려주십시오. 이것은 호흡이 이산화탄소를 생성하고 호흡이 나쁜 습관인지 묻는 것과 같습니다. 몇 분 동안 시도하십시오.


"단락 평가 없이도 제대로 작동하도록 다시 작성하고 다시 돌아와서 원하는 방식을 알려주십시오." -예, 이것은 파스칼의 기억을 되 찾습니다. 그리고 아니, 나는 그것을 좋아하지 않았다.
Thomas Padron-McCarthy

2

다른 답변에서 언급되지 않은 한 가지 고려 사항 : 때로는 이러한 검사를 수행하면 Null 개체 디자인 패턴 에 대한 리팩터링 가능성을 암시 할 수 있습니다 . 예를 들면 다음과 같습니다.

if (currentUser && currentUser.isAdministrator()) 
  doSomething();

다음과 같이 단순화 할 수 있습니다.

if (currentUser.isAdministrator())
  doSomething ();

경우 currentUser대체 구현에 약간의 '익명 사용자'또는 '널 (null) 사용자 디폴트로 사용자는 로그인하지 않은 경우.

아니 항상 코드 냄새,하지만 뭔가 생각합니다.


-4

나는 인기가 없어 질 것입니다. 그렇습니다. 나쁜 습관입니다. 경우 코드의 기능이에 의존 조건부 논리를 구현합니다.

 if(quickLogicA && slowLogicB) {doSomething();}

좋지만

if(logicA && doSomething()) {andAlsoDoSomethingElse();}

나쁘고, 아무도 아무도 동의하지 않습니까?!

if(doSomething() || somethingElseIfItFailed() && anotherThingIfEitherWorked() & andAlwaysThisThing())
{/* do nothing */}

추론 :

단순히 로직을 수행하지 않고 양쪽을 평가하면 코드 오류가 발생합니다. 이것은 문제가 아니라고 주장했으며 'and'연산자는 c #에 정의되어 있으므로 의미가 분명합니다. 그러나 나는 이것이 사실이 아니라고 주장한다.

이유 1. 역사

본질적으로 코드에서 기능을 제공하기 위해 컴파일러 최적화에 의존하고 있습니다 (원래 의도했던 것).

C #에서 언어 사양은 부울 'and'연산자가 단락을 보장한다고 보장하지만. 이것은 모든 언어와 컴파일러에 해당되는 것은 아닙니다.

wikipeda 다양한 언어 및 단락에 대한 자신의 포획 나열 http://en.wikipedia.org/wiki/Short-circuit_evaluation 당신이 많은 방법이 있습니다 수 있습니다. 그리고 여기에 들어 가지 않는 몇 가지 추가 문제가 있습니다.

특히, FORTRAN, Pascal 및 Delphi에는이 동작을 토글하는 컴파일러 플래그가 있습니다.

따라서 : 릴리스 용으로 컴파일 할 때 코드가 작동하지만 디버그 용 또는 대체 컴파일러 등으로 코드가 작동하지 않을 수 있습니다.

이유 2. 언어 차이

Wikipedia에서 볼 수 있듯이 부울 연산자가 처리 방법을 지정하더라도 모든 언어가 단락에 대해 동일한 접근 방식을 사용하는 것은 아닙니다.

특히 VB.Net의 'and'연산자는 단락되지 않으며 TSQL에는 몇 가지 특징이 있습니다.

현대적인 '솔루션'에는 javascript, regex, xpath 등과 같은 많은 언어가 포함될 가능성이 있으므로 코드 기능을 명확하게 할 때 이것을 고려해야합니다.

이유 3. 언어 내에서의 차이점

예를 들어 VB의 인라인 if는 if와 다르게 동작합니다. 다시 현대 응용 프로그램에서 코드는 코드 뒤와 인라인 웹 양식 사이에서 이동할 수 있으므로 의미의 차이를 알고 있어야합니다.

이유 4. 함수의 매개 변수를 점검하는 널의 특정 예

이것은이다 매우 좋은 예. 그것은 모든 사람이하는 일이지만 실제로 생각할 때 나쁜 습관입니다.

코드 줄이 상당히 줄어들 기 때문에 이런 종류의 검사를 보는 것이 매우 일반적입니다. 나는 누군가가 코드 검토에서 그것을 가져올 것이라고 의심합니다. (그리고 분명히 의견과 평가에서 인기가 있음을 알 수 있습니다!)

그러나 여러 가지 이유로 모범 사례에 실패합니다!

  1. 그것의 매우 다양한 원인에서 분명, 그 가장 좋은 방법은 당신이 그들을 사용하기 전에 유효성에 대한 귀하의 매개 변수를 확인하고 그들이 유효하지 않은 경우에 예외를 발생하는 것입니다. 코드 스 니펫은 주변 코드를 표시하지 않지만 다음과 같은 작업을 수행해야합니다.

    if (smartphone == null)
    {
        //throw an exception
    }
    // perform functionality
  2. 조건문 에서 함수를 호출하고 있습니다 . 함수 이름은 단순히 값을 계산한다는 것을 의미하지만 부작용을 숨길 수 있습니다. 예 :

    Smartphone.GetSignal() { this.signal++; return this.signal; }
    
    else if (smartphone.GetSignal() < 1)
    {
        // Do stuff 
    }
    else if (smartphone.GetSignal() < 2)
    {
        // Do stuff 
    }

    모범 사례는 다음과 같이 제안합니다.

    var s = smartphone.GetSignal();
    if(s < 50)
    {
        //do something
    }

이러한 모범 사례를 코드에 적용하면 숨겨진 조건부 사용을 통해 더 짧은 코드를 얻을 수있는 기회가 사라지는 것을 알 수 있습니다. 가장 좋은 방법은 스마트 폰이 null 인 경우를 처리 하기 위해 무언가하는 것 입니다.

나는 이것이 다른 일반적인 사용법의 경우이기도하다는 것을 알게 될 것이라고 생각합니다. 우리는 또한 다음을 기억해야합니다.

인라인 조건

var s = smartphone!=null ? smartphone.GetSignal() : 0;

그리고 무 합체

var s = smartphoneConnectionStatus ?? "No Connection";

좀 더 명확하게 유사한 짧은 코드 길이 기능을 제공합니다.

모든 요점을 지원하는 수많은 링크 :

https://stackoverflow.com/questions/1158614/what-is-the-best-practice-in-case-one-argument-is-null

C #의 생성자 매개 변수 유효성 검사-모범 사례

null을 기대하지 않으면 null을 검사해야합니까?

https://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx

https://stackoverflow.com/questions/1445867/why-would-a-language-not-use-short-circuit-evaluation

http://orcharddojo.net/orchard-resources/Library/DevelopmentGuidelines/BestPractices/CSharp

단락에 영향을주는 컴파일러 플래그의 예 :

Fortran : "sce | nosce 기본적으로 컴파일러는 XL Fortran 규칙을 사용하여 선택한 논리 표현식에서 단락 평가를 수행합니다. sce를 지정하면 컴파일러가 비 XL Fortran 규칙을 사용할 수 있습니다. 현재 규칙에서 허용하는 경우 컴파일러는 단락 평가를 수행합니다. 기본값은 nosce입니다. "

Pascal : "B-단락 평가를 제어하는 ​​플래그 지시문. 단락 평가에 대한 자세한 정보는 2 진 연산자의 피연산자 평가 순서를 참조하십시오. 자세한 정보는 명령 행 컴파일러의 -sc 컴파일러 옵션을 참조하십시오 ( "사용자 설명서에 설명되어 있습니다.")

Delphi : "Delphi는 기본적으로 단락 평가를 지원합니다. {$ BOOLEVAL OFF} 컴파일러 지시문을 사용하여 끌 수 있습니다."


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
세계 엔지니어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.