programing

C로 ':-!!'은 뭐예요?

bestprogram 2023. 4. 22. 11:00

C로 ':-!!'은 뭐예요?

이 이상한 매크로 코드를 /usr/include/linux/커널에서 우연히 발견했습니다.h:

/* Force a compilation error if condition is true, but also produce a
   result (of value 0 and type size_t), so the expression can be used
   e.g. in a structure initializer (or where-ever else comma expressions
   aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

무인 does does 가 뭐죠?:-!! 할수 수 do do do?

이것은 식 e가 0으로 평가될 수 있는지, 평가되지 않을 경우 빌드에 실패하는지 확인하는 방법입니다.

이름이 잘못되어 있기 에, 보다는 '마지막으로 하다'와.이것보다 더 비슷해야 합니다.BUILD_BUG_OR_ZERO 보다...ON_ZERO(이 이름이 헷갈리는지 아닌지에 대한 논의가 가끔 있었습니다.)

이 표현은 다음과 같이 읽어야 합니다.

sizeof(struct { int: -!!(e); }))
  1. (e) : 산식 : :e.

  2. !!(e): 하다:: 두 번 부정하다.0e == 0그 이외의 경우는, 「」를 참조해 주세요.1.

  3. -!!(e) : 2단계는 2단계입니다.00그 이외의 경우는, 「」를 참조해 주세요.-1.

  4. struct{int: -!!(0);} --> struct{int: 0;}: 0일 경우 폭 0의 익명 정수 비트필드를 가진 구조를 선언합니다.모든 게 정상이고 정상적으로 진행됩니다.

  5. struct{int: -!!(1);} --> struct{int: -1;}반면 0이 아니면 음수가 된다.음의 을 가진 비트필드를 선언하는 것은 컴파일 오류입니다.

그러면 구조체의 너비가 0인 비트필드와 음의 너비가 있는 비트필드 중 하나가 컴파일 오류입니다. ★★★★★★★★★★★★★★★★★★★★★★.sizeof필드에는 '우리'가 붙습니다.size_t 폭(이렇게 e★★★★★★★★★★★★★★★★★★」


다음과 같이 질문하는 사람도 있습니다.왜 그냥 사용하지 않는 거죠?

Keithmo의 답변은 다음과 같습니다.

이러한 매크로는 컴파일 타임테스트를 실장하고 assert()는 런타임테스트입니다

정확히 맞아.이전에 발견되었을 가능성이 있는 커널의 문제를 런타임에 검출하고 싶지 않습니다.이것은 운영 체제의 중요한 부분입니다.어느 정도까지 컴파일 시에 문제를 검출할 수 있기 때문에 더욱 좋습니다.

:비트필드입니다.★★★★★★에 대해서!!, 이것은 논리적인 이중 부정이므로 반환됩니다.0 또는 거짓으로1정말이에요.그리고 그-이치노

이것은 모두 잘못된 입력에 대해 컴파일러를 토하게 하는 속임수입니다.

BUILD_BUG_ON_ZERO★★★★★★★★★★★★★★★★★.-!!(e)는 음의 값으로 평가되어 컴파일 오류가 발생합니다. 이외의 경우는, 「」입니다.-!!(e)0으로 되며, 는 0.1비트필드입니다.에, 는 「」라고 됩니다.size_t0으로 하다

입력이 0이 아닐 경우 빌드가 실패하기 때문에 내 관점에서는 이름이 약합니다.

BUILD_BUG_ON_NULL.int.

일부 사람들은 이러한 매크로를 다음과 같이 혼동하는 것 같습니다.assert().

.assert()을 사용하다

업데이트:

C11 에서는, 이 키워드는 컴파일 시간 테스트를 작성하기 위해서 사용할 수 있습니다.이 키워드는 오래된 컴파일러용으로 코드가 작성되지 않는 한 사용해야 합니다.

이 구문에 대한 대안이 언급되지 않은 것이 매우 놀랍습니다.또 다른 일반적인 (그러나 오래된) 메커니즘은 정의되지 않은 함수를 호출하는 것이며, 자신의 어설션이 올바른 경우 함수 호출을 컴파일하기 위해 옵티마이저에 의존합니다.

#define MY_COMPILETIME_ASSERT(test)              \
    do {                                         \
        extern void you_did_something_bad(void); \
        if (!(test))                             \
            you_did_something_bad(void);         \
    } while (0)

이 메커니즘은 (최적화가 네이블로 되어 있는 한) 동작하지만 링크할 때까지 오류를 보고하지 않는 단점이 있습니다.이 때 your_did_something_bad() 함수의 정의를 찾을 수 없습니다.이것이 커널 개발자들이 음의 비트필드 폭과 음의 크기 배열과 같은 트릭을 사용하기 시작한 이유입니다(나중의 것은 GCC 4.4에서의 빌드 중단을 중지한 것입니다).

컴파일 타임 어설션의 필요성에 대해 GCC 4.3에서는 이 오래된 개념을 확장해도 컴파일 타임 에러를 생성할 수 있는 함수 속성을 도입했습니다.이러한 함수는, 「네거티브 사이즈」네거티브 사이즈 어레이」에러 메세지가 표시되지 않습니다.

#define MAKE_SURE_THIS_IS_FIVE(number)                          \
    do {                                                        \
        extern void this_isnt_five(void) __attribute__((error(  \
                "I asked for five and you gave me " #number))); \
        if ((number) != 5)                                      \
            this_isnt_five();                                   \
    } while (0)

실제로 Linux 3.9부터는 이 기능을 사용하는 매크로가 있으며, 이에 따라 대부분의 매크로가 업데이트되었습니다.그러나 이 매크로는 이니셜라이저로 사용할 수 없습니다.단, 스테이트먼트 표현식(다른 GCC C-확장)을 사용하면 할 수 있습니다.

#define ANY_NUMBER_BUT_FIVE(number)                           \
    ({                                                        \
        typeof(number) n = (number);                          \
        extern void this_number_is_five(void) __attribute__(( \
                error("I told you not to give me a five!"))); \
        if (n == 5)                                           \
            this_number_is_five();                            \
        n;                                                    \
    })

이 매크로는 파라미터가 1회 정확하게 평가되며(부작용이 있는 경우), 식이 5로 평가되거나 컴파일 시간 상수가 아닌 경우 "5를 주지 말라고 했습니다!"라고 하는 컴파일 시간 오류를 생성합니다.

그럼 왜 마이너스 크기의 비트 필드 대신 이 필드를 사용하지 않는 거죠?아아, 문장 표현식이 완전히 일정하더라도(즉, 컴파일 시간에 완전히 평가되고 그렇지 않으면 테스트를 통과할 수 있음) 문장 표현식의 사용을 포함하여 문장 표현식 사용에 많은 제약이 있다.또, 기능체외에서는 사용할 수 없다.

GCC가 이러한 단점을 곧 수정하여 상수문 식을 상수 이니셜라이저로 사용할 수 있기를 바랍니다.여기서의 과제는 법적 상수 표현이 무엇인지 정의하는 언어 사양입니다.C++11은 이 타입 또는 물건에만 constexpr 키워드를 추가했지만 C11에는 대응하는 키워드가 없습니다.C11은 이 문제의 일부를 해결하는 정적 어사션을 얻었지만 이러한 모든 단점을 해결하지는 못합니다.따라서 gcc가 -std=gnuc99 & -std=gnuc11 등을 통해 constexpr 기능을 확장하여 스테이트먼트 식 등에 사용할 수 있기를 바랍니다.

사이즈를 만들고 있습니다.0비트필드(조건이 false인 경우)에 대해-1(-!!1) 비트필드(조건이 true/non-zero인 경우).전자의 경우, 에러는 없고, int부재로 구조를 초기화한다.후자의 경우 컴파일 오류가 있습니다(사이즈는 없습니다).-1물론 비트필드가 생성됩니다).

언급URL : https://stackoverflow.com/questions/9229601/what-is-in-c