วิธีใดที่ดีที่สุดในการบรรลุการยืนยันแบบคงที่ของเวลาคอมไพล์ใน C (ไม่ใช่ C ++) โดยเน้นเฉพาะ GCC
วิธีใดที่ดีที่สุดในการบรรลุการยืนยันแบบคงที่ของเวลาคอมไพล์ใน 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!")
)
ฉันควรทราบว่าสิ่งนี้ถูกนำไปใช้ในเสียงดังรุ่นล่าสุดด้วย
error: expected declaration specifiers or '...' before 'sizeof'
สำหรับบรรทัดstatic_assert( sizeof(int) == sizeof(long int), "Error!);
(ฉันใช้ C ไม่ใช่ C ++ อยู่แล้ว)
_Static_assert( sizeof(int) == sizeof(long int), "Error!");
บน macine ของฉันฉันได้รับข้อผิดพลาด
error: expected declaration specifiers or '...' before 'sizeof'
AND error: expected declaration specifiers or '...' before string constant
(เขาอ้างถึง"Error!"
สตริง) (เช่น: ฉันกำลังคอมไพล์ด้วย -std = c11 เมื่อใส่การประกาศภายในฟังก์ชันทั้งหมดทำงานได้ดี (ล้มเหลวและประสบความสำเร็จตามที่คาดไว้))
_Static_assert
ไม่ได้ static_assert
C คุณต้อง `#include <assert.h> เพื่อรับมาโคร static_assert
สิ่งนี้ใช้ได้ในฟังก์ชันและขอบเขตที่ไม่ใช่ฟังก์ชัน (แต่ไม่ใช่ภายในโครงสร้างสหภาพแรงงาน)
#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);
}
หากไม่สามารถจับคู่การยืนยันเวลาคอมไพล์ได้ GCC จะสร้างข้อความที่เกือบเข้าใจได้ sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative
มาโครสามารถหรือควรเปลี่ยนเพื่อสร้างชื่อเฉพาะสำหรับ typedef (เช่นต่อ__LINE__
ท้ายstatic_assert_...
ชื่อ)
แทนที่จะเป็น ternary สิ่งนี้สามารถใช้ได้เช่นกัน#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);
}
UPDATE2: รหัสเฉพาะ GCC
GCC 4.3 (ฉันเดา) เปิดตัวแอตทริบิวต์ฟังก์ชัน "ข้อผิดพลาด" และ "คำเตือน" ถ้าการเรียกใช้ฟังก์ชันที่มีแอตทริบิวต์นั้นไม่สามารถกำจัดได้ด้วยการกำจัดรหัสตาย (หรือมาตรการอื่น ๆ ) ข้อผิดพลาดหรือคำเตือนจะถูกสร้างขึ้น สามารถใช้เพื่อยืนยันเวลาคอมไพล์ด้วยคำอธิบายความล้มเหลวที่ผู้ใช้กำหนด ยังคงเป็นตัวกำหนดว่าจะใช้ในขอบเขตเนมสเปซได้อย่างไรโดยไม่ต้องใช้ฟังก์ชันดัมมี่:
#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
-Og
) อาจเพียงพอสำหรับการทำงานนี้และไม่ควรรบกวนการดีบัก หนึ่งอาจพิจารณาทำให้การยืนยันแบบคงที่เป็น no-op หรือ runtime assert ถ้า__OPTIMIZE__
(และ__GNUC__
) ไม่ได้กำหนดไว้
__LINE__
เวอร์ชันใน gcc 4.1.1 ... ด้วยความรำคาญเป็นครั้งคราวเมื่อสองส่วนหัวที่แตกต่างกันมีหนึ่งในบรรทัดที่มีหมายเลขเดียวกัน!
ฉันรู้ว่าคำถามกล่าวถึง gcc อย่างชัดเจน แต่เพื่อความสมบูรณ์นี่คือการปรับแต่งสำหรับคอมไพเลอร์ของ Microsoft
การใช้อาร์เรย์ที่มีขนาดติดลบ typedef ไม่ได้ชักชวนให้clคายข้อผิดพลาดที่เหมาะสม มันบอกว่าerror C2118: negative subscript
. บิตฟิลด์ที่มีความกว้างเป็นศูนย์จะมีราคาที่ดีกว่าในแง่นี้ เนื่องจากสิ่งนี้เกี่ยวข้องกับการพิมพ์โครงสร้างเราจึงจำเป็นต้องใช้ชื่อประเภทที่ไม่ซ้ำกัน __LINE__
อย่าตัดมัสตาร์ด - เป็นไปได้ที่จะมีCOMPILE_TIME_ASSERT()
บรรทัดเดียวกันในส่วนหัวและไฟล์ต้นฉบับและคอมไพล์ของคุณจะแตก __COUNTER__
มาช่วย (และอยู่ใน gcc ตั้งแต่ 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__)
ตอนนี้
STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
ภายใต้cl
ให้:
ข้อผิดพลาด C2149: 'static_assertion_failed_use_another_compiler_luke': ฟิลด์บิตที่มีชื่อต้องไม่มีความกว้างเป็นศูนย์
Gcc ยังให้ข้อความที่เข้าใจได้:
ข้อผิดพลาด: ความกว้างเป็นศูนย์สำหรับบิตฟิลด์ 'static_assertion_failed_use_another_compiler_luke'
จากWikipedia :
#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
ฉันไม่แนะนำให้ใช้วิธีแก้ปัญหาโดยใช้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]
เนื่องจากstatic
คีย์เวิร์ดอาร์เรย์จะถูกกำหนดในเวลาคอมไพล์ โปรดทราบว่าการยืนยันนี้จะใช้ได้เฉพาะกับCOND
ที่ได้รับการประเมินในเวลาคอมไพล์ มันจะใช้ไม่ได้ (กล่าวคือคอมไพล์จะล้มเหลว) ด้วยเงื่อนไขที่อิงตามค่าในหน่วยความจำเช่นค่าที่กำหนดให้กับตัวแปร
หากใช้มาโคร STATIC_ASSERT () ด้วย__LINE__
จะเป็นไปได้ที่จะหลีกเลี่ยงการขัดแย้งหมายเลขบรรทัดระหว่างรายการในไฟล์. 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]
วิธีคลาสสิกคือการใช้อาร์เรย์:
char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];
ใช้งานได้เพราะถ้าการยืนยันเป็นจริงอาร์เรย์จะมีขนาด 1 และถูกต้อง แต่ถ้าเป็นเท็จขนาด -1 จะทำให้เกิดข้อผิดพลาดในการคอมไพล์
คอมไพเลอร์ส่วนใหญ่จะแสดงชื่อของตัวแปรและชี้ไปที่ส่วนขวาของโค้ดซึ่งคุณสามารถแสดงความคิดเห็นเกี่ยวกับการยืนยันได้ในที่สุด
#define STATIC_ASSERT()
มาโครประเภททั่วไปและให้ตัวอย่างทั่วไปมากขึ้นและเอาต์พุตคอมไพเลอร์ตัวอย่างจากตัวอย่างทั่วไปของคุณโดยใช้STATIC_ASSERT()
จะช่วยให้คุณได้รับคะแนนโหวตมากขึ้นและทำให้เทคนิคนี้มีความหมายมากขึ้นฉันคิดว่า
จาก Perl โดยเฉพาะperl.h
บรรทัด 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
หากstatic_assert
มี (จาก<assert.h>
) จะใช้ มิฉะนั้นหากเงื่อนไขเป็นเท็จระบบจะประกาศบิตฟิลด์ที่มีขนาดลบซึ่งทำให้การคอมไพล์ล้มเหลว
STMT_START
/ STMT_END
กำลังขยายมาโครเป็นdo
/ while (0)
ตามลำดับ
_Static_assert()
ตอนนี้ถูกกำหนดเป็น gcc สำหรับ C ทุกเวอร์ชันและ static_assert()
ถูกกำหนดไว้ใน C ++ 11 และใหม่กว่าSTATIC_ASSERT()
จึงใช้ได้ใน:g++ -std=c++11
) หรือใหม่กว่าgcc -std=c90
gcc -std=c99
gcc -std=c11
gcc
(ไม่ระบุมาตรฐาน)กำหนด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()
รหัสทำงาน แต่เงื่อนไขเป็นเท็จทำให้เกิดการยืนยันเวลาคอมไพล์):
$ gcc -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: ในฟังก์ชัน 'main'
static_assert.c: 78: 38: ข้อผิดพลาด: การยืนยันแบบคงที่ล้มเหลว: "(1> 2) ล้มเหลว"
# กำหนด STATIC_ASSERT (test_for_true ) _Static_assert ((test_for_true), "(" #test_for_true ") ล้มเหลว")
^
static_assert.c: 88: 5: หมายเหตุ: ในการขยายมาโคร 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
ตัวอย่างที่ 2:g++ -std=c++11
ผลลัพธ์ที่ดี(เช่นSTATIC_ASSERT()
รหัสทำงาน แต่เงื่อนไขเป็นเท็จทำให้เกิดการยืนยันเวลาคอมไพล์):
$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c && ./static_assert
static_assert.c: ในฟังก์ชัน 'int main ()'
static_assert.c: 74: 32: ข้อผิดพลาด: การยืนยันแบบคงที่ล้มเหลว: (1> 2) ล้มเหลว
#define _Static_assert static_assert / *static_assert
เป็นส่วนหนึ่งของ C ++ 11 หรือใหม่กว่า * /
^
static_assert.c: 78: 38: หมายเหตุ: ในการขยายมาโคร '_Static_assert'
# กำหนด STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true ") ล้มเหลว")
^
static_assert.c: 88: 5: หมายเหตุ: ในการขยายมาโคร 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
ตัวอย่างที่ 3: เอาต์พุต C ++ ที่ล้มเหลว (เช่น: รหัสยืนยันทำงานไม่ถูกต้องเลยเนื่องจากใช้ C ++ เวอร์ชันก่อน C ++ 11):
$ g ++ -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: 88: 5: Warning: identifier 'static_assert' เป็นคีย์เวิร์ดใน C ++ 11 [-Wc ++ 0x-compat]
STATIC_ASSERT (1> 2 );
^
static_assert.c: ในฟังก์ชัน 'int main ()'
static_assert.c: 78: 99: ข้อผิดพลาด: 'static_assert' ไม่ได้รับการประกาศในขอบเขตนี้
#define STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true " ) ล้มเหลว ")
^
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. /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
มาโครassert.h
?
static_assert()
ไม่มีใน C ดูที่นี่ด้วย: en.cppreference.com/w/cpp/language/static_assert -static_assert
มีรายการอยู่ "(ตั้งแต่ C ++ 11)" ความงามของคำตอบของฉันคือมันใช้งานได้ใน C90 ของ gcc และใหม่กว่ารวมถึง C ++ 11 และใหม่กว่าแทนที่จะเป็นใน C ++ 11 และใหม่กว่าเช่นstatic_assert()
. นอกจากนี้คำตอบของฉันซับซ้อนอะไรบ้าง มันเป็นเพียงคู่#define
s
static_assert
ถูกกำหนดไว้ใน C ตั้งแต่ C11 _Static_assert
มันเป็นแมโครที่จะขยาย en.cppreference.com/w/c/error/static_assert นอกจากนี้และตรงกันข้ามกับคำตอบของคุณ_Static_assert
ไม่มีใน c99 และ c90 ใน gcc (เฉพาะใน gnu99 และ gnu90) เป็นไปตามมาตรฐาน โดยพื้นฐานแล้วคุณทำงานพิเศษมากมายซึ่งจะก่อให้เกิดประโยชน์ก็ต่อเมื่อคอมไพล์ด้วย gnu90 และ gnu99 และทำให้ usecase เล็กลงอย่างไม่มีนัยสำคัญ
สำหรับผู้ที่คุณต้องการบางสิ่งที่เรียบง่ายและพกพาได้ แต่ไม่สามารถเข้าถึงคุณสมบัติ C ++ 11 ได้ฉันได้เขียนสิ่งนี้ไว้
ใช้STATIC_ASSERT
ตามปกติ (คุณสามารถเขียนสองครั้งในฟังก์ชันเดียวกันได้หากต้องการ) และใช้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
และหารด้วยตัวมันเอง สิ่งนี้ทำสองสิ่ง
หากเป็นศูนย์, id est, การยืนยันล้มเหลวจะทำให้เกิดข้อผิดพลาดหารด้วยศูนย์ (เลขคณิตถูกบังคับเนื่องจากพยายามประกาศอาร์เรย์)
ถ้าไม่ใช่ศูนย์จะทำให้ขนาดอาร์เรย์เป็น1
ปกติ ดังนั้นหากการยืนยันผ่านไปคุณจะไม่ต้องการให้มันล้มเหลวอีกต่อไปเพราะเพรดิเคตของคุณถูกประเมินเป็น-1
(ไม่ถูกต้อง) หรือเป็น232442
(เสียพื้นที่มาก IDK หากจะปรับให้เหมาะสม)
สำหรับหมายความว่าคุณสามารถเขียนได้หลายครั้ง
นอกจากนี้ยังหล่อให้STATIC_ASSERT
มันถูกห่อด้วยเครื่องหมายวงเล็บทำให้เป็นบล็อกซึ่งกำหนดขอบเขตของตัวแปรassert
void
ซึ่งเป็นวิธีที่ทราบกันดีในการกำจัดunused variable
คำเตือน
สำหรับGLOBAL_STATIC_ASSERT
แทนที่จะอยู่ในบล็อกโค้ดจะสร้างเนมสเปซ อนุญาตให้ใช้เนมสเปซภายนอกฟังก์ชันได้ unique
ระบุเป็นสิ่งจำเป็นที่จะหยุดคำจำกัดความขัดแย้งใด ๆ ถ้าคุณใช้คนนี้มากกว่าหนึ่งครั้ง
ทำงานให้ฉันใน GCC และ VS'12 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
//
สิ่งนี้ใช้ได้กับ 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
_Static_assert
เป็นส่วนหนึ่งของมาตรฐาน C11 และคอมไพเลอร์ใด ๆ ที่รองรับ C11 ก็จะมี