सी में स्थैतिक जोर


86

GCC पर विशेष जोर देने के साथ C (C C ++ नहीं) में संकलित समय स्थिर अभिसरण प्राप्त करने का सबसे अच्छा तरीका क्या है?

जवाबों:


90

C11 मानक _Static_assertकीवर्ड जोड़ता है ।

यह gcc-4.6 के बाद से लागू किया गया है :

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

पहले स्लॉट को एक अभिन्न स्थिर अभिव्यक्ति होने की आवश्यकता है। दूसरा स्लॉट एक निरंतर स्ट्रिंग शाब्दिक है जो लंबा ( _Static_assert(0, L"assertion of doom!")) हो सकता है ।

मुझे ध्यान देना चाहिए कि यह हाल के संस्करणों में भी लागू किया गया है।


4
[... लगता है कि gcc द्वारा लागू किया जा सकता है, clang द्वारा ...] आप अधिक मुखर हो सकते हैं कि; ;-) _Static_assertC11 मानक का हिस्सा है और कोई भी संकलक जो C11 का समर्थन करता है, उसके पास होगा।
पीपी

1
क्या इसे फ़ाइल स्कोप (किसी फ़ंक्शन के बाहर) में उपयोग किया जा सकता है? क्योंकि मुझे error: expected declaration specifiers or '...' before 'sizeof'लाइन मिलती है static_assert( sizeof(int) == sizeof(long int), "Error!); (मैं जिस तरह से C C C ++ का उपयोग नहीं कर रहा हूं)
user10607

@ user10607 मुझे आश्चर्य है कि यह काम नहीं करता है। रुको, आप अपनी त्रुटि स्ट्रिंग के अंत में एक उद्धरण याद कर रहे हैं। उसे रखो और वापस जाओ। यह मेरे लिए gcc-4.9 पर काम करता है: _Static_assert( sizeof(int) == sizeof(long int), "Error!");मेरे macine पर मुझे त्रुटि मिलती है।
ईमित्र

मेरे पास Ubuntu पर 4.8.2 है। लापता उद्धरण एक टिप्पणी टाइपो था (मेरे पास कोड में था)। हेडर के एक जोड़े को शामिल करने के बाद एक फ़ाइल में यह पहली पंक्ति है। कंपाइलर मुझे दो सटीक समान त्रुटियां देता है: error: expected declaration specifiers or '...' before 'sizeof'और error: expected declaration specifiers or '...' before string constant(वह "Error!"स्ट्रिंग का उल्लेख कर रहा है) (यह भी: मैं -std = c11 के साथ संकलित कर रहा हूं। जब एक फ़ंक्शन के अंदर घोषणा डालते हैं तो सभी अच्छी तरह से काम करता है (विफल रहता है और उम्मीद के
मुताबिक

2
@ user10607 मुझे कमांड लाइन पर -std = gnu11 भी बताना था। मैं वास्तव में आश्चर्यचकित हूं कि 4.8 और 4.8 के बीच अंतर होगा। मेरे पास सिर्फ एक लाइन वाला स्रोत है। मैंने C मानक का भी उपयोग _Static_assertनहीं किया C ++ ish static_assert। आपको static_assert मैक्रो प्राप्त करने के लिए `#include <assert.h> की आवश्यकता है।
ईमित्र

92

यह फंक्शन और नॉन-फंक्शन स्कोप (लेकिन स्ट्रक्चर्स, यूनियनों के अंदर नहीं) में काम करता है।

#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. मैक्रो को टाइपडिफ के लिए एक अनूठा नाम उत्पन्न करने के लिए परिवर्तित किया जा सकता है (यानी नाम __LINE__के अंत में संक्षिप्त static_assert_...करें)

  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); 
}

UPDATE2: जीसीसी विशिष्ट कोड

जीसीसी 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

1
विजुअल स्टूडियो में इसे "नेगेटिव सबस्क्रिप्ट" कहा गया है, जिसमें चर नाम का उल्लेख नहीं है ...
szx

नॉर्डिक मेनफ्रेम - आपके उत्तर में विकल्प 3 क्लैंग पर काम नहीं करता है।
इलाजर

1
अंतिम (GCC 4.3 + -specific) समाधान के बारे में: यह बहुत शक्तिशाली है, क्योंकि यह कुछ भी जांच सकता है, जो ऑप्टिमाइज़र समझ सकता है, लेकिन यह विफल रहता है यदि अनुकूलन सक्षम नहीं है। नंगे न्यूनतम अनुकूलन स्तर ( -Og) अक्सर काम करने के लिए पर्याप्त हो सकता है, हालांकि, और डिबगिंग में हस्तक्षेप नहीं करना चाहिए। यदि कोई __OPTIMIZE__(और __GNUC__) परिभाषित नहीं है, तो कोई स्टैटिक ऐसर को एक नो-ऑप या रनटाइम एस्टर बनाने पर विचार कर सकता है।
सोरेन लोवबोर्ग

लाइन संस्करण के साथ कोड स्निपेट में (अपडेट: पूर्णता के लिए, यहां 'लाइन' के साथ संस्करण है, जब संकलन करते हैं, तो यह लाइन (STATIC_ASSERT (X, static_assertion_line_ # _ L)) पर त्रुटि करता है, जिसे एक और जोड़कर ठीक किया जा सकता है। नीचे जैसा स्तर: #define COMPILE_TIME_ASSERT4 (X, L) static_assert (X, # L); #define COMPILE_TIME_ASSERT3 (X, L) COMPILE_TIME_ASSERT3 (X, "" पर जोर: ## L "");
सूंदर

मैं __LINE__संस्करण 4.1.1 में संस्करण के समान कुछ का उपयोग करता हूं ... कभी-कभी झुंझलाहट के साथ जब दो अलग-अलग हेडर एक ही संख्या रेखा पर एक होते हैं!
MM

10

सीएल

मुझे पता है कि इस प्रश्न का स्पष्ट रूप से उल्लेख किया गया है, लेकिन यहाँ पूर्णता के लिए Microsoft संकलक के लिए एक ट्वीक है।

नकारात्मक आकार के सरणी का उपयोग करते हुए टाइपडीफ एक सभ्य त्रुटि को थूकने के लिए सीएल को राजी नहीं करता है । यह सिर्फ कहता है error C2118: negative subscript। एक शून्य-चौड़ाई बिटफील्ड इस संबंध में बेहतर किराया करता है। चूंकि इसमें एक संरचना टाइप करना शामिल है, हमें वास्तव में अद्वितीय प्रकार के नामों का उपयोग करने की आवश्यकता है। __LINE__सरसों में कटौती नहीं करता है - COMPILE_TIME_ASSERT()हेडर और स्रोत फ़ाइल में एक ही लाइन पर होना संभव है , और आपका संकलन टूट जाएगा। __COUNTER__बचाव के लिए आता है (और यह 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' के लिए शून्य चौड़ाई


4

से विकिपीडिया :

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

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );

15
बेहतर होगा अगर आप सच्चे स्रोत से जुड़े: jaggersoft.com/pubs/CVu11_3.html
मैट जॉइनर

यह gcc 4.6 में काम नहीं करता है - यह कहता है "केस लेबल एक पूर्णांक स्थिरांक में कम नहीं होता है"। इसका एक बिंदु है।
लायसन

आप दोनों शायद अब तक वाया चले गए हैं, लेकिन मैंने अपना खुद का लिखना ( मेरा उत्तर देखें ) समाप्त कर दिया । मैंने आपकी सहायता के लिए आपके लिंक @MattJoiner का उपयोग किया
Hashbrown

और अगर आप परेशान हो सकते हैं, तो मुझे बताएं कि क्या यह आपके लिए काम करता है, @Liosan। मैंने केवल सी ++ में देरी करना शुरू कर दिया है, इसलिए मैं पार्टी में देर से आया हूं
हैशब्रोएन

विज़ुअल C ++ की तरह, इसमें 2010 से संस्करण के बाद से static_assert बिल्ट-इन है, और यह c ++ और c मोड दोनों में काम करता है। हालाँकि, इसमें c99 _Static_assert बिल्ट-इन नहीं है।
ddbug

3

मैं समाधान का उपयोग करने की अनुशंसा नहीं करूंगा 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जिसके साथ संकलन समय पर मूल्यांकन किया जाता है। यह उन शर्तों के साथ काम नहीं करेगा (जैसे संकलन विफल हो जाएगा) स्मृति में मूल्यों पर आधारित स्थितियों के साथ, जैसे कि चर को दिए गए मान।


4
जबकि यह काम करेगा, यह आपकी मेमोरी आवश्यकताओं को भी बढ़ाएगा।
शेरेरेबल्क

1
त्रुटि: 'static_assertion_INVALID_CHAR_SIZE' परिभाषित है, लेकिन इसका इस्तेमाल नहीं किया गया है -वरर = अप्रयुक्त-परिवर्तनीय]
एलेक्स

2

यदि 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]

1

क्लासिक तरीका एक सरणी का उपयोग कर रहा है:

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

यह काम करता है क्योंकि अगर यह दावा सही है कि सरणी का आकार 1 है और यह वैध है, लेकिन यदि यह गलत है तो -1 का आकार संकलन त्रुटि देता है।

अधिकांश संकलक चर का नाम दिखाएंगे और कोड के दाईं ओर इंगित करेंगे जहां आप दावे के बारे में अंतिम टिप्पणी छोड़ सकते हैं।


इसे एक सामान्य #define STATIC_ASSERT()प्रकार के मैक्रो में लपेटना और आपके सामान्य उदाहरणों से अधिक सामान्य उदाहरण और नमूना संकलक आउटपुट STATIC_ASSERT()प्रदान करना आपको बहुत अधिक उत्थान देगा और इस तकनीक को और अधिक समझ में आएगा।
गेब्रियल स्टेपल्स

मैं सहमत नहीं हूँ। संकलक विचार मैक्रोज़ को देखता है और अधिक भ्रमित संदेश देता है।
पाओलो.बोलज़ोनी

1

पर्ल से, विशेष रूप से 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)क्रमश।


1

चूंकि:

  1. _Static_assert() अब C के सभी संस्करणों के लिए gcc में परिभाषित किया गया है, और
  2. static_assert() C ++ 11 और बाद में परिभाषित किया गया है

STATIC_ASSERT()इसलिए निम्न सरल मैक्रो निम्न में काम करता है:

  1. सी ++:
    1. C ++ 11 ( g++ -std=c++11) या बाद का
  2. सी:
    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" 

उदाहरण:

Gcc 4.8.4 का उपयोग करके उबंटू में परीक्षण किया गया:

उदाहरण 1: अच्छा gccआउटपुट (यानी: STATIC_ASSERT()कोड काम करता है, लेकिन स्थिति झूठी थी, जिससे संकलन-समय जोर पड़ता है):

$ gcc -Wall -o-static_assert static_assert.c &&//atic_assert
static_assert.c: फ़ंक्शन में 'main'
static_assert.c: 78: 38: त्रुटि: स्टेटिक असेसमेंट विफल: "(1> 2) विफल"
#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);
^

उदाहरण 2: अच्छा g++ -std=c++11आउटपुट (यानी: STATIC_ASSERT()कोड काम करता है, लेकिन स्थिति झूठी थी, जिससे संकलन-समय जोर पड़ता है):

$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c &&//aticatic_assert
static_assert.c: फ़ंक्शन में 'int main ()'
static_assert.c: 74: 32: त्रुटि: static assertion विफल: (1> 2) विफल
#define _Static_assert static_assert / * static_assertC ++ 11 का हिस्सा है या बाद में * /
^
static_assert.c: 78: 38: ध्यान दें: मैक्रो के विस्तार में '_Static_assert'
#deineine STATIC_ASSERT (test_for_true) _Static_assert (test_tr_ueert)। "(" #test_for_true ") विफल")
^
static_assert.c: 88: 5: नोट: मैक्रो 'STATIC_ASSERT'
STATIC_ASSERT (1> 2) के विस्तार में;
^

उदाहरण 3: असफल C ++ आउटपुट (यानी: एस्टर कोड ठीक से काम नहीं करता है, क्योंकि यह C ++ 11 से पहले C ++ के संस्करण का उपयोग कर रहा है ):

$ g ++ -Wall -oall_assert static_assert.c &&/static_assert
static_assert.c: 88: 5: 5: चेतावनी: पहचानकर्ता 'static_assert' C ++ 11 [-WL ++ +
x- कॉमर्स ] STATIC_ASSERT (1> 2 ) में एक कीवर्ड है );
^
static_assert.c: फ़ंक्शन में 'int main ()'
static_assert.c: 78: 99: त्रुटि: 'static_assert' को इस दायरे में घोषित नहीं किया गया था
# STATIC_ASSERT (test_for_true )_Static_assert ((test_for_true), "(#test_forue) ) विफल ")
^
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;
}

सम्बंधित:

  1. मैक्रो को भेजे गए प्रकारों की जाँच करने के लिए static_assert का उपयोग करें [मेरा अपना उत्तर]
    1. https://en.cppreference.com/w/cpp/types/is_same
    2. https://en.cppreference.com/w/cpp/language/decltype
  2. मैक्रो को दिए गए प्रकारों की जाँच करने के लिए static_assert का उपयोग करें
  3. किसी मैक्रो को पास किए गए मापदंडों के प्रकारों की जांच करने के लिए सी में स्थिर मुखर का उपयोग कैसे करें

1
जब एक static_assertमैक्रो इन है तो इतना जटिल क्यों assert.h?
गुडबाय एसई

@KamiKaze, मैं आपके प्रश्न से आश्चर्यचकित हूं, क्योंकि ऐसा लगता है कि आपने वास्तव में मेरा उत्तर नहीं पढ़ा होगा? मेरे उत्तर की दूसरी पंक्ति यह सब कहती है: "static_assert () C ++ 11 और बाद में परिभाषित किया गया है"। इसलिए, static_assert()सी। में बिल्कुल भी उपलब्ध नहीं है। यहां भी देखें: en.cppreference.com/w/cpp/language/static_assert --it शो static_assert"(C ++ 11 के बाद से)" मौजूद है। मेरे उत्तर की सुंदरता यह है कि यह gcc के C90 और बाद में, साथ ही किसी भी C ++ 11 और बाद में, C ++ 11 के बजाय और बाद में, जैसे काम करता है static_assert()। इसके अलावा, मेरे जवाब के बारे में क्या जटिल है? यह केवल एक युगल है #define
गेब्रियल स्टेपल्स

static_assertC11 से C में परिभाषित किया गया है। यह एक मैक्रो है जो फैलता है _Static_asserten.cppreference.com/w/c/error/static_assert । इसके अतिरिक्त और आपके उत्तर के विपरीत _Static_assertg99 में c99 और c90 में उपलब्ध नहीं है (केवल gnu99 और gnu90 में)। यह मानक के अनुरूप है। मूल रूप से आप बहुत सारे अतिरिक्त काम करते हैं, केवल तभी लाभ होता है जब g9090 और gnu99 के साथ संकलित किया जाता है और जो वास्तविक usecase को तुच्छ रूप से छोटा कर देता है।
गुडबाय एसई

> "_Static_assert gcc में c99 और c90 में उपलब्ध नहीं है (केवल gnu99 और gnu90 में)"। मुझे पता है तुम्हारा क्या मतलब है। यह एक gcc एक्सटेंशन है इसलिए आप सही हैं। > "मूल रूप से आप बहुत सारे अतिरिक्त काम करते हैं"। मैं असहमत हूं; 2 अत्यंत सरल परिभाषित कोई अतिरिक्त काम का "बहुत" है। कहा जा रहा है, मैं देख रहा हूं कि अब आपका क्या मतलब है। मुझे अभी भी लगता है कि मैंने जो किया है वह उपयोगी है और यहां प्रस्तुत ज्ञान और उत्तरों के शरीर के लिए मूल्य जोड़ता है, इसलिए मुझे नहीं लगता कि यह नीचे की ओर गुण है। इसके अलावा, "सी 90 और बाद में" के बजाय "सीसीसी 90 और बाद में", या "जी 90 और बाद में" कहने में मेरी गलती, केवल मेरी टिप्पणी में थी, मेरे जवाब में नहीं।
गेब्रियल स्टेपल्स

जैसा कि यह तथ्यात्मक रूप से गलत था, एक गिरावट को उचित ठहराया गया था। यदि आप गलत कथनों को सही करेंगे तो मैं उत्तर की फिर से जाँच करूंगा और अपना पद छोड़ दूंगा। यदि आवश्यक न हो तो भी इस तरह के कोड को जोड़ना (इसलिए यदि आप gnu90 और g9999 के साथ काम नहीं करते हैं) स्पष्टता के लिए फायदेमंद नहीं है और अधिक अव्यवस्था जोड़ता है। यदि आपके पास usecase है तो यह इसके लायक हो सकता है। लेकिन मुझे आश्चर्य है कि usecase की दुर्लभता के बारे में जहां gnu99 / 90 और c ++ 11 की आवश्यकता है।
गुडबाय एसई

0

आप में से कुछ वास्तव में बुनियादी और पोर्टेबल चाहते हैं, लेकिन 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आइकॉन से प्राप्त नहीं करते हैं , और इसे अपने आप से विभाजित करते हैं। यह दो काम करता है।
यदि यह शून्य, आईडी एस्ट है, अभिकथन विफल हो गया है, तो यह शून्य त्रुटि से विभाजन का कारण होगा (अंकगणित मजबूर है क्योंकि यह एक सरणी घोषित करने की कोशिश कर रहा है)।
यदि यह शून्य नहीं है, तो यह सरणी आकार को सामान्य कर देता है 1। इसलिए यदि दावा पारित हो गया, तो आप इसे वैसे भी विफल नहीं करना चाहेंगे, क्योंकि आपके विधेय का मूल्यांकन -1(अमान्य), या 232442(बड़े पैमाने पर अंतरिक्ष की बर्बादी, आईडीके अगर इसे बाहर अनुकूलित किया जाएगा)।
इसके लिए STATIC_ASSERTइसे ब्रेसिज़ में लपेटा जाता है, यह इसे एक ब्लॉक बनाता है, जो चर को मापता हैassert, मतलब आप इसे कई बार लिख सकते हैं।
यह इसे भी डाल देता है void, जो कि छुटकारा पाने का एक ज्ञात तरीका हैunused variableचेतावनी।
के लिए GLOBAL_STATIC_ASSERT, बजाय एक कोड ब्लॉक में होने का, यह एक नाम स्थान उत्पन्न करता है। कार्यों के बाहर नाम स्थान की अनुमति है। uniqueयदि आप इसे एक से अधिक बार उपयोग करते हैं, तो किसी भी परस्पर विरोधी परिभाषा को रोकने के लिए एक पहचानकर्ता की आवश्यकता होती है।


मेरे लिए GCC और VS'12 C ++ पर काम किया


2
C. में कोई नामस्थान नहीं है
martinkunev

आह, वूप्स, सवाल गलत। ऐसा लगता है कि मैं वैसे भी C ++ का उत्तर
ढूंढने के

0

यह "हटाए गए अप्रयुक्त" विकल्प सेट के साथ काम करता है। मैं वैश्विक मापदंडों की जांच करने के लिए एक वैश्विक फ़ंक्शन का उपयोग कर सकता हूं।

//
#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
//

1
यदि यह बिल्कुल काम करता है, तो यह केवल एक निष्पादन योग्य स्रोत में ऐसा करेगा।
कोडर

0

इसने कुछ पुराने 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.