programing

참 조건(x = x ?: 1)에 대한 값을 할당하지 않고 3진수 연산자를 사용하는 이유는 무엇입니까?

minimums 2023. 7. 17. 20:50
반응형

참 조건(x = x ?: 1)에 대한 값을 할당하지 않고 3진수 연산자를 사용하는 이유는 무엇입니까?

안드로이드 오픈 소스 qemu 코드에서 나는 다음 코드 라인을 가로질러 실행했습니다.

machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */

이것은 단지 다음과 같이 말하는 혼란스러운 방식입니까?

if (machine->max_cpus) {
   ; //do nothing
} else {
 machine->max_cpus = 1;
}

그렇다면 다음과 같이 더 명확하지 않을까요?

if (machine->max_cpus == 0) machine->max_cpus = 1;

흥미롭게도, 이것은 gcc와 잘 컴파일되고 작동하지만, http://www.comeaucomputing.com/tryitout/ 에서는 컴파일되지 않습니다.

이는 GNU에서 C에 대한 모호한 확장으로 허용됩니다.

5.7 피연산자가 누락된 조건

조건식의 중간 피연산자는 생략될 수 있습니다.그런 다음 첫 번째 피연산자가 0이 아닌 경우 해당 값은 조건식의 값입니다.

그러므로, 그 표현은

 x ? : y

0이 아닐 경우 x의 값을 가지며, 그렇지 않을 경우 y의 값을 가집니다.

이 예는 완전히 다음과 같습니다.

 x ? x : y

이 간단한 경우 중간 피연산자를 생략하는 기능은 특별히 유용하지 않습니다.첫 번째 피연산자가 사용하거나 (매크로 인수인 경우) 부작용을 포함할 수 있을 때 유용해집니다.그런 다음 중간에 피연산자를 반복하면 부작용이 두 번 수행됩니다.중간 피연산자를 생략하면 이미 계산된 값이 다시 계산할 때의 바람직하지 않은 효과 없이 사용됩니다.

가독성 및 휴대성을 위해 이를 피하는 것이 좋습니다.저는 솔직히 C의 문법과 호환되지 않는 확장을 보고 놀랐습니다.

이것은 "조건이 참이면, 사용하라, 그렇지 않으면 이 다른 값을 사용하라"를 의미하는 GCC 확장자입니다.

machine->max_cpus = machine->max_cpus ?: 1;

의 줄임말입니다.

machine->max_cpus = machine->max_cpus ? machine->max_cpus : 1;

조건부에 부작용이 있는 경우에도 한 번만 실행됩니다.

gcc의 -pedicantic 플래그를 사용하면 다음과 같이 표시됩니다.

foo.c:5: 경고: ISO C는 ?: 식을 생략하는 것을 금지합니다.

이것은 GCC 확장판이며, 그 상태가 부작용을 가지고 있을 때 더 흥미롭고 유용하게 됩니다.

이 경우, 네, 저는 그것이 다른 무엇보다도 모호하다는 것에 동의합니다.

K&R BNF는 "?"와 ":" 사이에 식을 입력해야 함을 나타냅니다.저는 gcc가 진단 없이 그것을 편집해서는 안 된다고 생각합니다.

이것에 대한 또 다른 유용한 사례가 있습니다. 0을 반환할 수 있는 함수나 메서드를 호출할 때 중간 변수를 제거합니다. 두 번 호출하는 것을 피하고자 합니다.예를 들어 (Objective-C), 파일이 있는 경우 어레이로 압축을 풀고, 그렇지 않은 경우 빈 어레이를 반환하려고 합니다.

- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
    NSArray *backlog = @[];
    NSData *backlogData = [NSData dataWithContentsOfFile:path];
    if (backlogData)
    {
        backlog = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData] ?: backlog;
    }
    return backlog;
}

대안은 덜 간결합니다.

- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
    NSArray *backlog = @[];
    NSData *backlogData = [NSData dataWithContentsOfFile:path];
    if (backlogData)
    {
        NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
        if (tempArray != nil)
        {
            backlog = tempArray;
        }
    }
    return backlog;
}

또는 복수의 반품 등이 있는 더 추한.

- (NSArray*)hydrateBacklogFromFile:(NSString *path)
{
    NSData *backlogData = [NSData dataWithContentsOfFile:path];
    if (backlogData)
    {
        NSArray *tempArray = [NSKeyedUnarchiver unarchiveObjectWithData:backlogData];
        if (tempArray != nil)
        {
            return tempArray;
        }
    }
    return @[];
}

그래서 제가 꽤 읽을 수 있는 유용한 통사 설탕입니다.단점은.

  • 포인터를 암시적으로 부울로 변환합니다.이것은 오래된 C 규약이지만, 대부분의 현대 언어들은 그것을 허용하지 않고, 어떤 이식 작업도 복잡하게 만듭니다.

  • 다른 사람들이 말했듯이, 그것은 또한 비표준 확장이기 때문에 휴대성을 고려한다면 피해야 합니다.

다른 답변이 제목의 질문에 답하지 않고 태그도 가져가지 않는 것 같습니다.c을 덧붙입니다.따라서 저는 다른 답변을 추가합니다.

이 구문을 사용하여 if-문을 통해 코드가 추해지는 것을 방지합니다.

foo(1) == TRUE ?: error_quit("foo(1) failed");
foo(2) == TRUE ?: error_quit("foo(2) failed");
foo(3) == TRUE ?: error_quit("foo(3) failed");
foo(4) == TRUE ?: error_quit("foo(4) failed");

줄의 시작 부분에서 실제 함수 호출을 볼 수 있습니다.아래 버전과 비교하여 선두 제품이if함수 호출의 직접 보기를 방해합니다.

if (foo(1) == FALSE) error_quit("foo(1)" failed");
if (foo(2) == FALSE) error_quit("foo(2)" failed");
if (foo(3) == FALSE) error_quit("foo(3)" failed");    
if (foo(4) == FALSE) error_quit("foo(4)" failed");

또는 읽기가 더 어렵습니다.

if (foo(1) == FALSE){
  error_quit("foo(1)" failed");
}

if (foo(2) == FALSE){
  error_quit("foo(2)" failed");
}

if (foo(3) == FALSE){
  error_quit("foo(3)" failed");
}

if (foo(4) == FALSE){
  error_quit("foo(4)" failed");
}

언급URL : https://stackoverflow.com/questions/2806255/why-would-you-use-the-ternary-operator-without-assigning-a-value-for-the-true

반응형