programing

C의 정적 아사트

bestcode 2022. 8. 14. 12:02
반응형

C의 정적 아사트

C(C++가 아님)에서 특히 GCC에 중점을 두고 컴파일 타임 스태틱어사스토를 실현하는 최선의 방법은 무엇입니까?

에는 C11이 되어 있습니다._Static_assert키워드를 지정합니다.

이는 gcc-4.6부터 구현되었습니다.

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */

첫 번째 슬롯은 정수 표현식이어야 합니다.긴 입니다._Static_assert(0, L"assertion of doom!")를 참조해 주세요.

이 기능은 최신 버전의 clang에도 구현되어 있습니다.

이는 기능 및 비기능 범위(구조, 유니온 내부가 아님)에서 작동합니다.

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

STATIC_ASSERT(1,this_should_be_true); 

int main()
{
 STATIC_ASSERT(1,this_should_be_true); 
}
  1. 에서 거의 쉬운 됩니다.sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative

  2. 하여 typedef, concontainate "typedef")의할 수 __LINE__static_assert_...name를 합니다.

  3. 이 할 수 .#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]cc65 (6502 cpu ) 。

업데이트: 완전성을 위해 다음 버전이 있습니다.__LINE__

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X)    COMPILE_TIME_ASSERT2(X,__LINE__)

COMPILE_TIME_ASSERT(sizeof(long)==8); 
int main()
{
    COMPILE_TIME_ASSERT(sizeof(int)==4); 
}

업데이트 2: GCC 고유 코드

GCC 4.3(아마도)에서는 "error" 및 "warning" 함수 속성이 도입되었습니다.데드 코드 제거(또는 다른 수단)를 통해 해당 속성을 가진 함수에 대한 콜을 제거할 수 없는 경우 오류 또는 경고가 발생합니다.이를 사용하여 컴파일 시간을 사용자 정의 장애 설명과 함께 어설트할 수 있습니다.더미 함수에 의존하지 않고 이름 공간 범위에서 사용할 수 있는 방법을 결정해야 합니다.

#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })

// never to be called.    
static void my_constraints()
{
CTC(sizeof(long)==8); 
CTC(sizeof(int)==4); 
}

int main()
{
}

그리고 이것은 다음과 같습니다.

$ gcc-mp-4.5 -m32 sas.c 
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true

이유:

  1. _Static_assert()C 및 .
  2. static_assert() C++11 이후에 정의되어 있습니다(또, C11에서도, C++11 의 경우는, 에 대한 편리 매크로로서 정의되어 있습니다)._Static_assert(); 여기와 여기참조해 주세요.

for음음 for for for for의 간단한 매크로를 다음에 나타내는 입니다.STATIC_ASSERT()에 다음과 같은 경우에 사용할 수식어, 수식어, 수식어, 수식어, 수식어, 수식어, 수식어, 수식어, 수식어 수식어 등이 있습니다.

  1. C++:
    1. C++11)g++ -std=c++11)는,
  2. C:
    1. gcc -std=c90
    2. gcc -std=c99
    3. gcc -std=c11
    4. gcc 지정 없음 ('std')

의 정의STATIC_ASSERT음음음같 뭇매하다

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")

사용방법:

STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed" 

예:

Ubuntu에서 gcc 4.8.4를 사용하여 테스트 완료:

1: 양호gcc 력즉 ( (즉즉,STATIC_ASSERT()코드는 동작하지만 조건이 false이므로 컴파일 타임 아사트가 발생합니다).

- - o static _ assert _ . c & . _ assert $ gcc - o static _ assert static _ assert . c & . / static _ 아사트
'static_assert.c: 'main' 에서
: 실패: "(> 2) failed static_disc.c:78:38: "static_disc.c: 78:38: " " " " " : " ( 1 > 2) " "
STATIC_ASSERT "(" define STATIC_ASSERT(test_for_true))_Static_assert((test_for_true), "(" #test_for_true " ) failed )
^
: 'STATIC_ASSERT의 중.c:88:5:':'STATIC_ASSERT' 。
STATIC_ASSERT(1 > 2);
^

2: 양호g++ -std=c++11 력즉 ( (즉즉,STATIC_ASSERT()코드는 동작하지만 조건이 false이므로 컴파일 타임 아사트가 발생합니다).

- - = static_params . / static_c & . / static_params = c+++11 -o static_params static.c & . / static_params
' mainstatic_assert.c: "int main()"
: failed: (1 > 2) failed static_disc.c:74:32: " ": " (1 > 2) "
# 의 _ _ Static_assert static_assert /*static_assertC++11 의 입니다.* /
^
의 시:78:38:static : ' _ Static _ assert ' 。
STATIC_ASSERT "(" define STATIC_ASSERT(test_for_true))_Static_assert((test_for_true), "(" #test_for_true " ) failed )
^
: 'STATIC_ASSERT의 중.c:88:5:':'STATIC_ASSERT' 。
STATIC_ASSERT(1 > 2);
^

3: 실패한 C++ 출력(즉, C++11보다 이전 버전의 C++를 사용하고 있기 때문에 아사트 코드가 전혀 올바르게 동작하지 않습니다):

- - o static_assert .c & . / $ g++ - o static_assert static_assert.c & . / static_assert
warning:는 C[-static_assert.c:88:5 의 입니다.ID 'static_assert' C++11 입니다.
STATIC_ASSERT(1 > 2);
^
' mainstatic_assert.c: "int main()"
이 .c:78:99: "static_signatic"이.
STATIC_ASSERT "(" define STATIC_ASSERT(test_for_true))_Static_assert((test_for_true), "(" #test_for_true " ) failed )
^
: 'STATIC_ASSERT의 중.c:88:5:':'STATIC_ASSERT' 。
STATIC_ASSERT(1 > 2);
^

전체 테스트 결과는 다음과 같습니다.

/*
static_assert.c
- test static asserts in C and C++ using gcc compiler

Gabriel Staples
4 Mar. 2019 

To be posted in:
1. https://stackoverflow.com/questions/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
2. https://stackoverflow.com/questions/3385515/static-assert-in-c/7287341#7287341

To compile & run:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert
    
-------------
TEST RESULTS:
-------------

1. `_Static_assert(false, "1. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  NO

2. `static_assert(false, "2. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             NO
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    NO
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

3. `STATIC_ASSERT(1 > 2);` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

*/

#include <stdio.h>
#include <stdbool.h>

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")


int main(void)
{
    printf("Hello World\n");

    /*_Static_assert(false, "1. that was false");*/
    /*static_assert(false, "2. that was false");*/
    
    STATIC_ASSERT(1 > 2);

    return 0;
}

연관된:

  1. static_assert를 사용하여 매크로에 전달된 유형을 확인합니다(내 답변).
  2. https://en.cppreference.com/w/cpp/types/is_same
  3. https://en.cppreference.com/w/cpp/language/decltype
  4. static_assert를 사용하여 매크로에 전달된 유형을 확인합니다.
  5. C에서 정적 어사션을 사용하여 매크로에 전달된 파라미터의 유형을 확인하는 방법

이 솔루션을 사용하는 것은 권장하지 않습니다.typedef:

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

과 " " "typedef이치노예를 들어 블록 범위의 다음 코드가 컴파일됩니다.

int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);

대신 이것을 추천합니다(C99).

#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]

그유 the the because because 。static키워드. 어레이는 컴파일 시에 정의됩니다.이 어설션은 다음 명령어에서만 동작합니다.COND컴파일 시 평가됩니다.변수에 할당된 값 등 메모리 값을 기반으로 하는 조건에서는 작동하지 않습니다(컴파일이 실패합니다).

일반적인 방법은 어레이를 사용하는 것입니다.

char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];

어설션이 true이면 어레이의 사이즈가 1이고 유효하지만 false일 경우 사이즈가 -1이면 컴파일 오류가 발생하므로 동작합니다.

대부분의 컴파일러는 변수의 이름을 표시하고 코드의 오른쪽 부분을 가리킵니다.여기에서 어설션에 대한 최종적인 코멘트를 남길 수 있습니다.

Perl에서, 특히 회선 3455 (<assert.h>

/* STATIC_ASSERT_DECL/STATIC_ASSERT_STMT are like assert(), but for compile
   time invariants. That is, their argument must be a constant expression that
   can be verified by the compiler. This expression can contain anything that's
   known to the compiler, e.g. #define constants, enums, or sizeof (...). If
   the expression evaluates to 0, compilation fails.
   Because they generate no runtime code (i.e.  their use is "free"), they're
   always active, even under non-DEBUGGING builds.
   STATIC_ASSERT_DECL expands to a declaration and is suitable for use at
   file scope (outside of any function).
   STATIC_ASSERT_STMT expands to a statement and is suitable for use inside a
   function.
*/
#if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
/* static_assert is a macro defined in <assert.h> in C11 or a compiler
   builtin in C++11.  But IBM XL C V11 does not support _Static_assert, no
   matter what <assert.h> says.
*/
#  define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
#else
/* We use a bit-field instead of an array because gcc accepts
   'typedef char x[n]' where n is not a compile-time constant.
   We want to enforce constantness.
*/
#  define STATIC_ASSERT_2(COND, SUFFIX) \
    typedef struct { \
        unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
    } _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#  define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#  define STATIC_ASSERT_DECL(COND)    STATIC_ASSERT_1(COND, __LINE__)
#endif
/* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
   error (static_assert is a declaration, and only statements can have labels).
*/
#define STATIC_ASSERT_STMT(COND)      STMT_START { STATIC_ASSERT_DECL(COND); } STMT_END

ifstatic_assert '에서).<assert.h>가 사용됩니다가 사용됩니다.그렇지 않으면 조건이 false일 경우 마이너스사이즈의 비트필드가 선언되어 컴파일이 실패합니다.

STMT_STARTSTMT_END는 「」로 확장되고 ?dowhile (0)각각 다음과 같다.

cl

이 질문에 gcc가 명시적으로 언급되어 있는 것은 알고 있습니다만, 여기서 설명하는 것은 Microsoft 컴파일러의 수정입니다.

음수 크기의 배열 typedef를 사용해도 cl이 적절한 오류를 발생시키지 않습니다.라고만 써있어요.error C2118: negative subscript이 점에서는 제로폭 비트필드가 효과적입니다.이것은 구조체의 타이핑과 관련되어 있기 때문에, 우리는 반드시 독특한 타입의 이름을 사용할 필요가 있습니다. __LINE__머스타드를 자르지 않습니다.★★★★★★★★★★★★★★★★★★,COMPILE_TIME_ASSERT()헤더와 소스 파일의 같은 줄에 있으면 컴파일이 중단됩니다. __COUNTER__) (4.3 gcc에 포함) (4.3 gcc에 포함)

#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
    typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
        CTASTR(static_assertion_failed_,__COUNTER__)

지금이다

STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)

아래cl

오류 C2149: 'static_assertion_failed_use_another_compiler_luke': 이름 있는 비트 필드의 너비는 0일 수 없습니다.

GCC는 다음과 같은 알기 쉬운 메시지도 제공합니다.

오류: 비트 필드 'static_syslog_use_another_syslog_syslog'의 너비가 0입니다.

STATIC_ASSERT를 STATIC_ASSERT()와 함께 __LINE__c행의 경합을 하려면 , .c 파일의 엔트리를 지정합니다.__INCLUDE_LEVEL__.

예를 들어 다음과 같습니다.

/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y )      BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y )   BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y )  X##Y
#define STATIC_ASSERT(x)        typedef char \
        BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
                    BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]

C++11 기능에 액세스 할 수 없는, 매우 기본적인 휴대성을 원하는 분들을 위해서, 딱 맞는 것을 썼습니다.
STATIC_ASSERTnormal 에 따라 두번쓸 수 "(필요에 따라 두 번 쓸 수 있습니다)"를 사용합니다.GLOBAL_STATIC_ASSERT첫 번째 매개 변수로 고유한 구문을 사용하여 함수 외부에 있습니다.

#if defined(static_assert)
#   define STATIC_ASSERT static_assert
#   define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
#   define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
#   define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif

GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");

int main(int c, char** v) {
    (void)c; (void)v;
    STATIC_ASSERT(1 > 0, "yo");
    STATIC_ASSERT(1 > 0, "yo");
//    STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
    return 0;
}

★★★★
먼저 실제 주장이 있는지 확인합니다.사용할 수 있다면 사용하고 싶은 것이 확실합니다.
'아주머니'로합니다.pred얼음과 그것을 스스로 나눈다.을 사용하다
이 값이 0(id est)이면 어설션이 실패하면 0으로 나누기 오류가 발생합니다(배열을 선언하려고 하므로 산술이 강제됩니다).
으로 정규화합니다.1 만약에 이 되었다면, 가 ' 좋겠다', '실패하지 않았으면 ' 이렇게 왜냐하면 당신의 술어가 다음과 같이 평가되었기 때문입니다.-1 (부정적232442(IDK).
★★★의 STATIC_ASSERT이 됩니다.이 블록은 변수 합니다.이러한', '따라서', '따라서', '따이러한', '따라서'로 지정합니다.assert아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 맞다.
그것은 또한 그것을 에 던진다.void은 잘 있는 unused variable★★★★★★ 。
★★★의 GLOBAL_STATIC_ASSERT코드 블록에 있는 대신 네임스페이스를 생성합니다.네임스페이스는 기능 외부에서 사용할 수 있습니다. a.unique이 정의를 두 번 이상 사용하는 경우 충돌하는 정의를 중지하려면 식별자가 필요합니다.


GCC 및 VS'12 C++에서 근무했습니다.

Wikipedia에서:

#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );

이 조작은, 「미사용의 삭제」옵션이 설정되어 있는 경우에 유효합니다.하나의 글로벌 함수를 사용하여 글로벌 파라미터를 확인할 수 있습니다.

//
#ifndef __sassert_h__
#define __sassert_h__

#define _cat(x, y) x##y

#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
    _cat(ASSERT_WARNING_, ln)(); \
}

#define sassert(exp) _sassert(exp, __LINE__)

#endif //__sassert_h__

//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
    sassert(TXB_TX_PKT_SIZE < 3000000);
    sassert(TXB_TX_PKT_SIZE >= 3000000);
    ...
}

//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//

이건 옛날 gcc한테 먹혔어.버전명을 잊어버려서 죄송합니다.

#define _cat(x, y) x##y

#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]

#define sassert(exp) _sassert((exp), __LINE__)

//
sassert(1 == 2);

//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134)  main.c  /test/source/controller line 134    C/C++ Problem

C11보다 오래된 버전의 C에서는 독자적인 스태틱어사션을 구축할 수 있습니다.다음은 이전 버전의 GCC에서 테스트한 것입니다.

C11을할 수 C11을 사용하는 것이 적절합니다.#include <assert.h>를 사용합니다.static_assert.

/** @file
 * STATIC_ASSERT allows you to do compile time assertions at file scope or in a function.
 * @param expr: a boolean expression that is valid at compile time.
 * @param msg: a "message" that must also be a valid identifier, i.e. message_with_underscores
 */

#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
    (!!sizeof(struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
    extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
    #define STATIC_ASSERT(expr, msg)   \
    extern char STATIC_ASSERTION__##msg[1]; \
    extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */

#define STATIC_ASSERT_ARRAY_LEN(array, len) \
    STATIC_ASSERT(sizeof(array)/sizeof(array[0]) == len, array##_wrong_size);

#endif // STATIC_ASSERT_H

이 아이디어는 기본적으로 Hashbrown의 답변과 동일합니다.단, 어레이 도우미와 gnuc 전용 케이스가 있습니다.

출처 : https://github.com/apache/qpid-dispatch/blob/f2e205c733558102006ed6dd0a44453c9821c80a/include/qpid/dispatch/static_assert.h#L23-L44

언급URL : https://stackoverflow.com/questions/3385515/static-assert-in-c

반응형