Cách tốt nhất để đạt được thời gian biên dịch xác nhận tĩnh trong C (không phải C ++), đặc biệt nhấn mạnh vào GCC là gì?
Cách tốt nhất để đạt được thời gian biên dịch xác nhận tĩnh trong C (không phải C ++), đặc biệt nhấn mạnh vào GCC là gì?
Câu trả lời:
Tiêu chuẩn C11 thêm _Static_assert
từ khóa.
Điều này được triển khai kể từ gcc-4.6 :
_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
Vị trí đầu tiên cần phải là một biểu thức hằng tích phân. Khe thứ hai là một ký tự chuỗi không đổi có thể dài ( _Static_assert(0, L"assertion of doom!")
).
Tôi cần lưu ý rằng điều này cũng được thực hiện trong các phiên bản gần đây của clang.
error: expected declaration specifiers or '...' before 'sizeof'
cho dòng static_assert( sizeof(int) == sizeof(long int), "Error!);
(Tôi đang sử dụng C không phải C ++ bằng cách)
_Static_assert( sizeof(int) == sizeof(long int), "Error!");
Trên macine của tôi, tôi gặp lỗi.
error: expected declaration specifiers or '...' before 'sizeof'
AND error: expected declaration specifiers or '...' before string constant
(anh ấy đang tham chiếu đến "Error!"
chuỗi) (cũng như: Tôi đang biên dịch với -std = c11. Khi đặt khai báo bên trong một hàm, tất cả đều hoạt động tốt (không thành công và thành công như mong đợi))
_Static_assert
không phải C ++ ish static_assert
. Bạn cần `#include <khẳng định.h> để nhận macro static_assert.
Điều này hoạt động trong phạm vi chức năng và phi chức năng (nhưng không hoạt động bên trong các cấu trúc, liên kết).
#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);
}
Nếu xác nhận thời gian biên dịch không thể khớp, thì một thông báo gần như dễ hiểu sẽ được tạo bởi GCC sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative
Macro có thể hoặc nên được thay đổi để tạo ra một tên duy nhất cho typedef (nghĩa là nối __LINE__
ở cuối static_assert_...
tên)
Thay vì một bậc ba, điều này cũng có thể được sử dụng #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]
, nó sẽ hoạt động ngay cả trên trình biên dịch cc65 cũ đã gỉ (cho cpu 6502).
CẬP NHẬT:
Vì lợi ích hoàn chỉnh, đây là phiên bản với__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);
}
UPDATE2: Mã cụ thể của GCC
GCC 4.3 (tôi đoán) đã giới thiệu các thuộc tính chức năng "lỗi" và "cảnh báo". Nếu một lệnh gọi đến một hàm có thuộc tính đó không thể bị loại bỏ thông qua loại bỏ mã chết (hoặc các biện pháp khác) thì một lỗi hoặc cảnh báo sẽ được tạo ra. Điều này có thể được sử dụng để xác nhận thời gian biên dịch với các mô tả lỗi do người dùng xác định. Nó vẫn còn để xác định cách chúng có thể được sử dụng trong phạm vi không gian tên mà không cần dùng đến một hàm giả:
#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()
{
}
Và đây là cách nó trông như thế này:
$ 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
-Og
Tuy nhiên, mức tối ưu hóa tối thiểu ( ) thường có thể đủ để tính năng này hoạt động và không ảnh hưởng đến việc gỡ lỗi. Người ta có thể xem xét việc làm cho xác nhận tĩnh trở thành xác nhận không hoạt động hoặc thời gian chạy nếu __OPTIMIZE__
(và __GNUC__
) không được xác định.
__LINE__
phiên bản trong gcc 4.1.1 ... đôi khi hơi khó chịu khi hai tiêu đề khác nhau có một tiêu đề trên cùng một dòng được đánh số!
Tôi biết câu hỏi đề cập rõ ràng đến gcc, nhưng chỉ để hoàn thiện ở đây là một tinh chỉnh cho các trình biên dịch của Microsoft.
Sử dụng typedef mảng có kích thước âm không thuyết phục cl tìm ra một lỗi phù hợp. Nó chỉ nói error C2118: negative subscript
. Trường bit có chiều rộng bằng không có giá tốt hơn về mặt này. Vì điều này liên quan đến việc gõ một cấu trúc, chúng ta thực sự cần sử dụng các tên kiểu duy nhất. __LINE__
không cắt ngang - có thể có một COMPILE_TIME_ASSERT()
dòng trên cùng một dòng trong tiêu đề và tệp nguồn, và biên dịch của bạn sẽ bị hỏng. __COUNTER__
đến để giải cứu (và nó đã có trong gcc kể từ 4.3).
#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__)
Hiện nay
STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
dưới cl
cho:
error C2149: 'static_assertion_failed_use_aosystem_compiler_luke': trường bit được đặt tên không được có chiều rộng bằng 0
Gcc cũng đưa ra một thông điệp dễ hiểu:
error: zero width cho trường bit 'static_assertion_failed_use_aosystem_compiler_luke'
Từ Wikipedia :
#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
Tôi KHÔNG khuyên bạn nên sử dụng giải pháp bằng cách sử dụng typedef
:
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
Khai báo mảng với typedef
từ khóa KHÔNG đảm bảo được đánh giá tại thời điểm biên dịch. Ví dụ: mã sau trong phạm vi khối sẽ biên dịch:
int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);
Tôi muốn giới thiệu điều này thay thế (trên C99):
#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]
Vì static
từ khóa, mảng sẽ được xác định tại thời điểm biên dịch. Lưu ý rằng xác nhận này sẽ chỉ hoạt động với COND
những gì được đánh giá tại thời điểm biên dịch. Nó sẽ không hoạt động với (tức là quá trình biên dịch sẽ thất bại) với các điều kiện dựa trên các giá trị trong bộ nhớ, chẳng hạn như các giá trị được gán cho các biến.
Nếu sử dụng macro STATIC_ASSERT () với __LINE__
, có thể tránh xung đột số dòng giữa một mục nhập trong tệp .c và một mục nhập khác trong tệp tiêu đề bằng cách bao gồm __INCLUDE_LEVEL__
.
Ví dụ :
/* 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ách cổ điển là sử dụng một mảng:
char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];
Nó hoạt động bởi vì nếu xác nhận là đúng, mảng có kích thước 1 và nó hợp lệ, nhưng nếu nó sai, kích thước -1 sẽ gây ra lỗi biên dịch.
Hầu hết các trình biên dịch sẽ hiển thị tên của biến và trỏ đến phần bên phải của mã nơi bạn có thể để lại nhận xét cuối cùng về xác nhận.
#define STATIC_ASSERT()
macro loại chung và cung cấp thêm các ví dụ chung và đầu ra trình biên dịch mẫu từ các ví dụ chung của bạn bằng cách sử dụng STATIC_ASSERT()
sẽ cung cấp cho bạn nhiều lượt ủng hộ hơn và tôi nghĩ rằng kỹ thuật này có ý nghĩa hơn.
Từ Perl, cụ thể là perl.h
dòng 3455 (đã <assert.h>
bao gồm trước):
/* 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
Nếu static_assert
có sẵn (từ <assert.h>
), nó được sử dụng. Ngược lại, nếu điều kiện sai, một trường bit có kích thước âm sẽ được khai báo, điều này làm cho quá trình biên dịch không thành công.
STMT_START
/ STMT_END
là các macro mở rộng thành do
/ while (0)
, tương ứng.
_Static_assert()
hiện được định nghĩa bằng gcc cho tất cả các phiên bản của C và static_assert()
được định nghĩa trong C ++ 11 trở lênSTATIC_ASSERT()
Do đó, macro đơn giản sau đây hoạt động trong:g++ -std=c++11
) trở lêngcc -std=c90
gcc -std=c99
gcc -std=c11
gcc
(không chỉ định std)Xác định STATIC_ASSERT
như sau:
/* 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")
Bây giờ sử dụng nó:
STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed"
Đã kiểm tra trong Ubuntu bằng gcc 4.8.4:
Ví dụ 1:gcc
đầu ra tốt (nghĩa là: STATIC_ASSERT()
mã hoạt động, nhưng điều kiện sai, gây ra xác nhận thời gian biên dịch):
$ gcc -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: Trong hàm 'main'
static_assert.c: 78: 38: error: static khẳng định không thành công: "(1> 2) không thành công"
#define STATIC_ASSERT (test_for_true ) _Static_assert ((test_for_true), "(" #test_for_true ") không thành công")
^
static_assert.c: 88: 5: lưu ý: trong phần mở rộng của macro 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
Ví dụ 2:g++ -std=c++11
đầu ra tốt (nghĩa là: STATIC_ASSERT()
mã hoạt động, nhưng điều kiện là sai, gây ra xác nhận thời gian biên dịch):
$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c && ./static_assert
static_assert.c: Trong hàm 'int main ()'
static_assert.c: 74: 32: lỗi: xác nhận tĩnh không thành công: (1> 2) không thành công
#define _Static_assert static_assert / *static_assert
là một phần của C ++ 11 trở lên * /
^
static_assert.c: 78: 38: lưu ý: khi mở rộng macro '_Static_assert'
#define STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true ") không thành công")
^
static_assert.c: 88: 5: lưu ý: trong phần mở rộng của macro 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
Ví dụ 3: đầu ra C ++ không thành công (nghĩa là: mã khẳng định không hoạt động bình thường, vì điều này đang sử dụng phiên bản C ++ trước C ++ 11):
$ g ++ -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: 88: 5: warning: mã định danh 'static_assert' là một từ khóa trong C ++ 11 [-Wc ++ 0x-compat]
STATIC_ASSERT (1> 2 );
^
static_assert.c: Trong hàm 'int main ()'
static_assert.c: 78: 99: error: 'static_assert' không được khai báo trong phạm vi này
#define STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true " ) không thành công ")
^
static_assert.c: 88: 5: lưu ý: khi mở rộng macro '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. /programming/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
2. /programming/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;
}
static_assert
macro trong assert.h
?
static_assert()
không có sẵn trong C. Xem thêm tại đây: en.cppreference.com/w/cpp/language/static_assert --it cho thấy static_assert
tồn tại "(kể từ C ++ 11)". Cái hay của câu trả lời của tôi là nó hoạt động trong C90 của gcc trở lên, cũng như bất kỳ C ++ 11 nào trở lên, thay vì chỉ trong C ++ 11 trở lên, như static_assert()
. Ngoài ra, câu trả lời của tôi có gì phức tạp? Nó chỉ có một vài #define
s.
static_assert
được định nghĩa trong C kể từ C11. Nó là một macro mở rộng đến _Static_assert
. vi.cppreference.com/w/c/error/static_assert . Ngoài ra và tương phản với câu trả lời của bạn _Static_assert
không có trong c99 và c90 trong gcc (chỉ trong gnu99 và gnu90). Điều này là phù hợp với tiêu chuẩn. Về cơ bản, bạn thực hiện rất nhiều công việc bổ sung, điều đó chỉ mang lại lợi ích nếu được biên dịch với gnu90 và gnu99 và điều này làm cho usecase thực tế nhỏ đi không đáng kể.
Đối với những người bạn muốn một cái gì đó thực sự cơ bản và di động nhưng không có quyền truy cập vào các tính năng của C ++ 11, tôi đã viết điều này.
Sử dụng STATIC_ASSERT
bình thường (bạn có thể viết nó hai lần trong cùng một hàm nếu bạn muốn) và sử dụng GLOBAL_STATIC_ASSERT
bên ngoài các hàm với một cụm từ duy nhất làm tham số đầu tiên.
#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;
}
Giải thích:
Đầu tiên nó kiểm tra xem bạn có xác nhận thực sự hay không, mà bạn chắc chắn sẽ muốn sử dụng nếu nó có sẵn.
Nếu bạn không, nó xác nhận bằng cách lấy pred
icate của bạn và chia nó cho chính nó. Điều này làm được hai điều.
Nếu nó là 0, id est, thì xác nhận không thành công, nó sẽ gây ra lỗi chia cho 0 (số học bị ép buộc vì nó đang cố gắng khai báo một mảng).
Nếu nó không phải là 0, nó sẽ bình thường hóa kích thước mảng thành 1
. Vì vậy, nếu xác nhận được thông qua, bạn sẽ không muốn nó bị lỗi vì vị từ của bạn được đánh giá là -1
(không hợp lệ) hoặc là 232442
(lãng phí dung lượng lớn, IDK nếu nó sẽ được tối ưu hóa).
Vì STATIC_ASSERT
nó được bao bọc trong dấu ngoặc nhọn, điều này làm cho nó trở thành một khối, phạm vi biếnassert
, nghĩa là bạn có thể viết nó nhiều lần.
Nó cũng chuyển nó đến void
, đây là một cách đã biết để loại bỏ các unused variable
cảnh báo.
Cho GLOBAL_STATIC_ASSERT
, thay vì trong một khối mã, nó tạo ra một không gian tên. Không gian tên được phép bên ngoài các chức năng. Cần có số unique
nhận dạng để ngăn chặn mọi định nghĩa xung đột nếu bạn sử dụng định nghĩa này nhiều lần.
Đã làm việc cho tôi trên GCC và VS'12 C ++
Điều này hoạt động, với tùy chọn "loại bỏ không sử dụng" được đặt. Tôi có thể sử dụng một hàm toàn cục để kiểm tra các tham số toàn cục.
//
#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
//
Điều này đã làm việc cho một số gcc cũ. Xin lỗi vì tôi quên đó là phiên bản nào:
#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
_Static_assert
là một phần của tiêu chuẩn C11 và bất kỳ trình biên dịch nào hỗ trợ C11, sẽ có nó.