ProgramingTip

if (expr) 대신 if (!! (expr)) 사용

bestdevel 2020. 11. 13. 23:51
반응형

if (expr) 대신 if (!! (expr)) 사용


Texas Instruments에서 SensorTag 대해 제공하는 한 예제 코드를 읽는 동안 다음 스 니펫을 발견했습니다.

void SensorTagIO_processCharChangeEvt(uint8_t paramID) { 
    ...

    if (!!(ioValue & IO_DATA_LED1)) {
        PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON);
    } else {
        PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF);
    }

    if (!!(ioValue & IO_DATA_LED2)) {
        PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON);
    } else {
        PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF);
    }

    if (!!((ioValue & IO_DATA_BUZZER))) {
        Clock_start(buzzClockHandle);
    }
    ...
}

선언은 다음과 있음 (동일한 파일에 있음).

#define IO_DATA_LED1   0x01
static uint8_t ioValue;

어떤 if (!!(ioValue & IO_DATA_LED1))이점을 제공 if (ioValue & IO_DATA_LED1)합니까?


논리가 아닌 ( !) 연산자를 두 번 적용하는 것은 값을 0 또는 1로 정규화하는 목적을 가지고 있습니다. if- 문의 제어는 존재하지 않습니다. if 문은 값이 0인지 0이 아닌지에만 관심이 있고 작은 !!춤은 완전히 쓸모가 없습니다.

일부 코딩 스타일 가이드는 이러한 종류의 춤을 요구할 수 있으며, 이것이 게시 게시 한 TI 코드가이를 수행하는 이유 일 수 있습니다. 그래도 그렇게하는 것을 본 적이 없습니다.


!!x, 또는는 참 (0이 숫자 또는 Null이 아닌 포인터)이면 !(!x)1을 의미 x하고, 값 0을 의미합니다 x != 0. 이는 C99와 거의 동일 (_Bool)x하지만 C99 이전의 컴파일러 또는 개발자가 선택하지 않은 컴파일러에서 사용할 수 있습니다. C99 구현 (예 : MOS 6502를 대상으로하는 cc65 ).

조건부 전체는 다음과 가변합니다.

if (ioValue & IO_DATA_LED1) {
    /* what to do if the IO_DATA_LED1 bit is true */
} else {
    /* what to do if the IO_DATA_LED1 bit is false */
}

C에서는 "두 값의 비트 AND가 0이 아니면 블록 실행"을 의미합니다.

그러나 일부 코딩 스타일 가이드 는 논리 AND ( )에 대한 오타로 &하여 if명령문 조건 의 최상위 수준에서 비트 AND ( )를 금지 할 수 있습니다 &&. 많은 컴파일러가 진단을 제공하는 (동등 비교) =대신 (할당) 을 사용하는 것과 동일한 종류의 실수 ==입니다. GCC 경고 옵션 은 다음과 같은 진단을 설명합니다.

-Wlogical-op: 식에서 의심스러운 논리 연산자 사용에 대해 경고합니다. 여기에는 비트 연산자가 예상되는 것에서 논리 연산자를 사용하는 것이 포함됩니다.

-Wparentheses: 진실 값이 예상되는 경우에 할당이있는 경우와 같이 특정 많은 경우에서 괄호가 생략 된 경우 경고

같은 의역의 사용 (a & B) != 0, (_Bool)(a & B)또는 !!(a & B)컴파일러와 다른 개발자와 통신을하는 비트 연산자의 사용은 의도적이었다.

!!xJavaScript에서 관련 답변을 참조하십시오 .


MSVC bool에서 if명령문 에서 정수를 암시 적으로 변환하면 경고가 숨겨집니다. 는를 통해 !!. 다른 컴파일러에도 사용할 수 있습니다.

따라서 해당 경고가 활성화 된 상태로 코드가 실행되고 모든 경고를 오류로 처리하기로 결정하고 가정하면 !!"예,이 정수가 bool"가 되기를 원합니다. "라고 말하는 짧고 이식 가능한 방법 입니다.


비트 단위에 대한 컴파일러 경고를 항상하는 것이 &가장 가능성이 높지만 다음에서 가독성을 위해 열거을 추가하는 리팩토링의 결과 일 수도 있습니다.

PIN_setOutputValue(int,int,bool); //function definition
PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1));
PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2));
//note: the !! is necessary here in case sizeof ioValue > sizeof bool
//otherwise it may only catch the 1st 8 LED statuses as @M.M points out

에 :

enum led_enum {
  Board_LED_OFF = false,
  Board_LED_ON = true
};
PIN_setOutputValue(int,int,bool); //function definition
//...
PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1)?Board_LED_ON:Board_LED_OFF);
PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2)?Board_LED_ON:Board_LED_OFF);

80 자 제한을 초과했기 때문에 다음으로 리팩토링되었습니다.

if (!!(ioValue & IO_DATA_LED1)) {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF);
}

if (!!(ioValue & IO_DATA_LED2)) {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF);
}

나는 가독성을 초기 버전을 선호했지만,이 버전은 코드 줄이 방식으로 때 일반적입니다 (각 상태에 대한 변수를 선언하지 않고 각 상태를 표시 설정 한 다음이를 사용하는 것이 놀랍습니다).

이 "모범 사례"코드의 다음 버전은 다음과 달라집니다.

bool boardled1State;
bool boardled2State;
//...

boardled1State = !!(ioValue & IO_DATA_LED1);
boardled2State = !!(ioValue & IO_DATA_LED2);
//...

if (boardled1State) {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF);
}

if (boardled2State) {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF);
}
//... and so on

모두 다음과 같이 할 수 있습니다.

for (int i=0;i<numleds;i++)
        PIN_setOutputValue(hGpioPin, i ,!!(ioValue & (1<<i)));

OP는 이전 코딩 관용구를 찾고 있습니다 -BITD (오늘날).

  1. 의 주요 용도는 0에 대해 테스트 하는 대신에 !!식을로 변환하는 C 구현을 처리 하는 것입니다.if(expr)int

를 0으로 expr변환 int한 다음 테스트 할 때 어떤 일이 발생하는지 고려 합니다. (C89 이후로는 테스트가 0에 대한 직접 테스트 여야하므로 부적합입니다.)

int i;
long li;
double d;

// no problems
if (i & 5) ...
if (d > 4.0) ...

// problems
if (li & 0x10000) ...  (Hint: int is 16-bit)
if (d)                 (d might have a value outside `int` range.

// fix
if (!!(li & 0x10000))
if (!!d)

따라서 이전 C89 컴파일러와 비 적합 C89 이상 !!에서는 그 약점에 대처했습니다. 일부 오래된 습관은 죽는 데 오랜 시간이 걸립니다.

  1. 에서 초기 C ++ , 전혀 없었다 bool유형. 따라서 신뢰도를 테스트하려는 코드는 !!관용구 를 사용해야했습니다.

    class uint256;  // Very wide integer
    uint256 x;
    
    // problem  as (int)x may return just the lower bits of x
    if (x) 
    
    // fix
    if (!!x) 
    
  2. (bool)정의 된 연산자 가없는 경우 오늘날 C ++에서 어떤 일이 발생합니까 (나는 이것이 C 질문이라는 것을 알고 있습니다) . (int)연산자가 사용 되지 않습니까? 이로 인해 # 2와 동일한 문제가 발생합니다. 많은 초기에 관해서는 C 및 C ++ 코드베이스를 사용하여 동기화에 보관 된 !!같은 구조로 한 관련성을 if (!!x).


!!오늘날 작업을 사용 하지만 더 이상 중요한 빈도로 발생하지 않는 문제를 해결하기 때문에 확실히 선호되지 않았습니다.

참고 URL : https://stackoverflow.com/questions/35523023/using-if-expr-instead-of-if-expr

반응형