मैं प्रीप्रोसेसर मैक्रो में "साइज़ोफ़" का उपयोग कैसे कर सकता हूं?


95

क्या sizeofप्रीप्रोसेसर मैक्रो में ए का उपयोग करने का कोई तरीका है ?

उदाहरण के लिए, कुछ वर्षों में स्थितियों का एक टन रहा है जिसमें मैं कुछ करना चाहता था:

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

सटीक चीज़ जो मैं यहाँ देख रहा हूँ, वह पूरी तरह से बनी हुई है - बिंदु यह है कि, मैं अक्सर इन प्रकारों (आकार या संरेखण) में रखना पसंद करता हूं, किसी डेटा-संरचना को संशोधित करने वाले किसी व्यक्ति के विरुद्ध पहरा देने के लिए संकलन-समय की जाँच करता है जो गलत या पुन: बना सकता है। आकार की चीजें जो उन्हें तोड़ देगी।

कहने की आवश्यकता नहीं है - मैं sizeofऊपर वर्णित तरीके से एक का उपयोग करने में सक्षम नहीं दिखाई देता ।


यह सटीक कारण है कि बिल्ड सिस्टम मौजूद है।
15:मोन तोथ

3
यही सटीक कारण है कि # निर्देश सीधे हमेशा दोहरे उद्धरण चिह्नों में होना चाहिए ("नहीं" के कारण निरंतर चरित्र स्थिर)।
जेन्स

1
नमस्कार @ ब्रैड। कृपया अपने स्वीकार किए गए उत्तर को बिना उत्तर के उत्तर में बदलने पर विचार करें, क्योंकि इस दौरान, वर्तमान में स्वीकृत उत्तर थोड़ा अप्रचलित हो गया है।
बोडो थिसन

@BodoThiesen किया गया।
ब्रैड

जवाबों:


69

इसे करने के कई तरीके हैं। यदि sizeof(someThing)समान हो तो स्निपेट के बाद कोई कोड नहीं होगा PAGE_SIZE; अन्यथा वे एक संकलन-समय त्रुटि उत्पन्न करेंगे।

1. C11 रास्ता

C11 से शुरू करके आप उपयोग कर सकते हैं static_assert(आवश्यकता #include <assert.h>)।

उपयोग:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2. कस्टम मैक्रो

यदि आप केवल एक संकलन-समय त्रुटि प्राप्त करना चाहते हैं जब sizeof(something)आप जो अपेक्षा नहीं करते हैं, तो आप निम्नलिखित मैक्रो का उपयोग कर सकते हैं:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

उपयोग:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

यह लेख विवरण में बताता है कि यह क्यों काम करता है।

3. एमएस-विशिष्ट

Microsoft C ++ कंपाइलर पर आप C_ASSERT मैक्रो (आवश्यकता #include <windows.h>) का उपयोग कर सकते हैं , जो कि धारा 2 में वर्णित एक के समान एक चाल का उपयोग करता है।

उपयोग:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);

4
...यह पागलपन है। यह स्वीकृत उत्तर, @ ब्रैड (ओपी) क्यों नहीं है?
इंजीनियर

BUILD_BUG_ON का अच्छा संदर्भ।
पेट्र वेपेक

2
जीएनयू gcc(संस्करण 4.8.4 पर परीक्षण) (लिनक्स) में मैक्रो काम नहीं करता है । पर ((void)sizeof(...साथ यह त्रुटियों expected identifier or '(' before 'void'और expected ')' before 'sizeof'। लेकिन सिद्धांत रूप में size_t x = (sizeof(...इसके बजाय इरादा के रूप में काम करता है। आपको परिणाम को किसी तरह "उपयोग" करना होगा। इसे किसी फ़ंक्शन या वैश्विक दायरे में कई बार कॉल करने की अनुमति देने के लिए , कुछ का extern char _BUILD_BUG_ON_ [ (sizeof(...) ];उपयोग बार-बार किया जा सकता है (कोई साइड-इफेक्ट, वास्तव में _BUILD_BUG_ON_कहीं भी संदर्भ नहीं)।
जॉनब्रवे

2011 की तुलना में बहुत अधिक समय के लिए स्थैतिक का उपयोग करते हुए एक वर्ष हो गया है।
दान


70

sizeofप्री-प्रोसेसर मैक्रो में " " का उपयोग करने के लिए वैसे भी क्या है ?

नहीं, सशर्त निर्देश सशर्त अभिव्यक्तियों का प्रतिबंधित सेट लेते हैं; sizeofअनुमति नहीं है चीजों में से एक है।

स्रोत से पार्स होने से पहले (कम से कम वैचारिक रूप से) प्रीप्रोसेसिंग निर्देशों का मूल्यांकन किया जाता है, इसलिए उनका आकार प्राप्त करने के लिए अभी तक कोई प्रकार या चर नहीं हैं।

हालांकि, सी में संकलन-समय के दावे प्राप्त करने की तकनीकें हैं (उदाहरण के लिए, इस पृष्ठ को देखें )।


शानदार लेख - चतुर समाधान! हालांकि आपको प्रशासन करना होगा - उन्होंने वास्तव में सी सिंटैक्स को धकेल दिया है ताकि यह काम करने के लिए सीमित हो सके! : -ओ
ब्रैड

1
बाहर मुड़ता है - जैसा कि लेख भी कहता है - मैं अभी लिनक्स कर्नेल कोड बना रहा हूं - और कर्नेल में पहले से ही एक परिभाषित है - BUILD_BUG_ON - जहां कर्नेल चीजों के लिए इसका उपयोग करता है: BUILD_BUG_ON (sizeof (char)! = 8)
ब्रैड

2
@ ब्रैड BUILD_BUG_ON और निश्चित रूप से गलत कोड उत्पन्न करने वाले अन्य लोग जो संकलित करने में विफल रहेंगे (और प्रक्रिया में कुछ गैर-स्पष्ट त्रुटि संदेश दे सकते हैं)। वास्तव में # कथन नहीं है, इसलिए आप इसके आधार पर कोड के ब्लॉक को बाहर नहीं कर सकते।
केल्टर

10

मुझे पता है कि यह एक देर से जवाब है, लेकिन माइक के संस्करण में जोड़ने के लिए, यहां एक संस्करण है जो हम उपयोग करते हैं जो किसी भी मेमोरी को आवंटित नहीं करता है। मैं मूल आकार की जांच के साथ नहीं आया था, मैंने इसे इंटरनेट पर वर्षों पहले पाया था और दुर्भाग्य से लेखक को संदर्भित नहीं कर सकता। अन्य दो एक ही विचार के विस्तार हैं।

क्योंकि वे टाइप्डिफ हैं, कुछ भी आवंटित नहीं है। नाम में __LINE__ के साथ, यह हमेशा एक अलग नाम होता है, इसलिए इसे कॉपी किया जा सकता है और जहां आवश्यक हो, चिपकाया जा सकता है। यह MS Visual Studio C कंपाइलर और GCC आर्म कंपाइलर में काम करता है। यह CodeWarrior में काम नहीं करता है, CW पुनर्वित्त के बारे में शिकायत करता है, __LINE__ प्रीप्रोसेसर निर्माण का उपयोग नहीं करता है।

//Check overall structure size
typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1];

//check 8 byte alignment for flash write or similar
typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1];

//check offset in structure to ensure a piece didn't move
typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];

यह वास्तव में एक मानक सी परियोजना के लिए वास्तव में अच्छी तरह से काम करता है ... मुझे यह पसंद है!
एशले डंकन

1
यह शून्य आवंटन के कारण सही उत्तर होना चाहिए। एक परिभाषित में और भी बेहतर:#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
रेनॉड सेराटो

p__LINE__ एक अद्वितीय नाम नहीं देता है। यह एक चर के रूप में p__LINE__ का उत्पादन करता है। आपको प्रीप्रो मैक्रो की आवश्यकता होगी और sys / cdefs.h से __CONCAT का उपयोग करना होगा।
कोरो

9

मुझे पता है कि यह धागा वास्तव में पुराना है लेकिन ...

मेरा समाधान:

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

जब तक कि अभिव्यक्ति शून्य के बराबर होती है, तब तक यह ठीक संकलित करता है। और कुछ भी और यह वहाँ ठीक हो जाता है। क्योंकि चर बाहरी है यह कोई जगह नहीं लेगा, और जब तक कोई भी इसे संदर्भित नहीं करता (जो वे नहीं करेंगे) यह लिंक त्रुटि का कारण नहीं होगा।

मुखर मैक्रो के रूप में लचीला नहीं है, लेकिन मैं जीसीसी के अपने संस्करण में संकलित करने के लिए ऐसा नहीं कर सका और यह होगा ... और मुझे लगता है कि यह कहीं भी बस के बारे में संकलन करेगा।


6
कभी भी दो अंडरस्कोर से शुरू होने वाले अपने मैक्रोज़ का आविष्कार करें। यह रास्ता पागलपन (उर्फ अपरिभाषित व्यवहार ) है।
जेन्स

इस पृष्ठ पर सूचीबद्ध उदाहरणों का एक समूह हैं pixelbeat.org/programming/gcc/static_assert.html
portforwardpodcast

जब हाथ gcc संकलक के साथ संकलित नहीं करता है। अपेक्षित त्रुटि "त्रुटि: वैरिएबल मॉडिफाइड ' CHECK ' फाइल स्कोप में"
thunderbird

@ जेन्स आप सही हैं लेकिन यह सचमुच एक मैक्रो नहीं है, यह एक चर घोषणा है। बेशक, यह मैक्रोज़ के साथ हस्तक्षेप कर सकता है।
मेलेबियस

4

मौजूदा उत्तर सिर्फ यह दिखाते हैं कि एक प्रकार के आकार के आधार पर "संकलन-समय के जोर" के प्रभाव को कैसे प्राप्त किया जाए। यह इस विशेष मामले में ओपी की जरूरतों को पूरा कर सकता है, लेकिन ऐसे अन्य मामले हैं जहां आपको वास्तव में एक प्रकार के आकार के आधार पर प्रीप्रोसेसर सशर्त की आवश्यकता होती है। यह कैसे करना है:

अपने आप को थोड़ा C प्रोग्राम लिखें जैसे:

/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* 'int' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }

संकलन करें। अपनी पसंदीदा स्क्रिप्टिंग भाषा में एक स्क्रिप्ट लिखें, जो उपरोक्त C प्रोग्राम को चलाता है और इसके आउटपुट को कैप्चर करता है। C हैडर फ़ाइल उत्पन्न करने के लिए उस आउटपुट का उपयोग करें। उदाहरण के लिए, यदि आप रूबी का उपयोग कर रहे थे, तो ऐसा लग सकता है:

sizeof_int = `./sizeof_int`
File.open('include/sizes.h','w') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER

फिर अपने Makefile या अन्य बिल्ड स्क्रिप्ट में एक नियम जोड़ें, जो इसे बनाने के लिए उपरोक्त स्क्रिप्ट चलाएगा sizes.h

sizes.hजहाँ भी आपको आकार के आधार पर प्रीप्रोसेसर कंडीशन का उपयोग करने की आवश्यकता हो, उन्हें शामिल करें ।

किया हुआ!

(क्या आपने कभी ./configure && makeकोई प्रोग्राम बनाने के लिए टाइप किया है? क्या configureस्क्रिप्ट मूल रूप से ऊपर की तरह है ...)


इसकी एक ऐसी ही बात है जब आप "ऑटोकॉनफ" जैसे उपकरणों का उपयोग कर रहे हैं।
अलेक्जेंडर स्टोह्र

4

अगले मैक्रो के बारे में क्या:

/* 
 * Simple compile time assertion.
 * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
 */
#define CT_ASSERT(exp, message_identifier) \
    struct compile_time_assertion { \
        char message_identifier : 8 + !(exp); \
    }

उदाहरण के लिए टिप्पणी में MSVC कुछ बताता है:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits

1
यह प्रश्न का उत्तर नहीं है क्योंकि आप इसे #ifप्रीप्रोसेसर निर्देश में उपयोग नहीं कर सकते हैं ।
विस्फ़ोटक -

1

इस चर्चा के लिए एक संदर्भ के रूप में, मैं रिपोर्ट करता हूं कि कुछ संकलक आकार-प्रकार () पूर्व-प्रोसेसर समय प्राप्त करते हैं।

JamesMcNellis का उत्तर सही है, लेकिन कुछ संकलक इस सीमा से गुजरते हैं (यह शायद सख्त एएनएसआई का उल्लंघन करता है)।

इस के रूप में, मैं आईएआर सी-कंपाइलर (शायद पेशेवर माइक्रोकंट्रोलर / एम्बेडेड प्रोग्रामिंग के लिए अग्रणी) का उल्लेख करता हूं।


क्या अापको उस बारे में पूर्ण विशवास है? IAR का दावा है कि उनके कंपाइलर ISO C90 और C99 मानकों के अनुरूप हैं, जो sizeofप्रीप्रोसेसिंग समय पर मूल्यांकन की अनुमति नहीं देते हैं । sizeofसिर्फ एक पहचानकर्ता के रूप में माना जाना चाहिए।
कीथ थॉम्पसन

6
1998 में, comp.std.c न्यूज़ग्रुप पर किसी ने लिखा: "यह उन दिनों में अच्छा था जब #if (sizeof(int) == 8)वास्तव में (कुछ संकलकों पर) काम किया गया था।" प्रतिक्रिया: "मेरे समय से पहले रहा होगा।", डेनिस रिची का था।
कीथ थॉम्पसन

देर से जवाब के लिए क्षमा करें ... हाँ, मुझे यकीन है, मेरे पास 8/16/32 बिट्स माइक्रोकंट्रोलर, रेनेसस कंपाइलर (आर 8 और आरएक्स दोनों) के लिए संकलित कोड के उदाहरण हैं।
ग्राज़ियानो गवर्नर

वास्तव में,
ग्रैजियानो गवर्नर

जब तक मानक इसका निषेध नहीं करता है तब तक इसका उल्लंघन नहीं होता है। तब मैं इसे एक दुर्लभ और गैर-मानक सुविधा कहूंगा - इस प्रकार आप संकलक स्वतंत्रता और प्लेटफ़ॉर्म पोर्टेबिलिटी को बनाए रखने के लिए नियमित मामलों में इससे बचेंगे।
अलेक्जेंडर स्टोह्र

1

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x)) शायद काम कर जाये


यह एक दिलचस्प समाधान है, हालांकि यह केवल परिभाषित चर के साथ काम करता है, न कि प्रकारों के साथ। एक और समाधान जो प्रकार के साथ काम करता है लेकिन चर के साथ नहीं होगा:#define SIZEOF_TYPE(x) (((x*)0) + 1)
greydet

7
यह काम नहीं करता है क्योंकि आप अभी भी एक #ifशर्त के भीतर इसके परिणाम का उपयोग नहीं कर सकते हैं। यह कोई लाभ नहीं प्रदान करता है sizeof(x)
अंतरजय

1

C11 में _Static_assertकीवर्ड जोड़ा जाता है। इसका उपयोग इस तरह किया जा सकता है:

_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")

0

मेरे पोर्टेबल c ++ कोड में ( http://www.starmessagesoftware.com/cpcclibrary/ ) मेरी कुछ संरचनाओं या कक्षाओं के आकार पर एक सुरक्षित गार्ड लगाना चाहता था।

प्रीप्रोसेसर के लिए एक त्रुटि को फेंकने के लिए एक रास्ता खोजने के बजाय (जो कि आकार के साथ काम नहीं कर सकता है) (जैसा कि यहां बताया गया है), मुझे यहां एक समाधान मिला जिससे कंपाइलर एक त्रुटि फेंकने का कारण बनता है। http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99

मुझे अपने कंपाइलर (xcode) में त्रुटि करने के लिए उस कोड को अनुकूलित करना पड़ा:

static union
{
    char   int8_t_incorrect[sizeof(  int8_t) == 1 ? 1: -1];
    char  uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
    char  int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
    char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
    char  int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
    char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};

2
क्या आप सुनिश्चित हैं कि उन "”1" को कभी भी 0xFFFF ... FF के रूप में व्याख्यायित नहीं किया जाएगा, जिससे आपका प्रोग्राम सभी पते की मेमोरी का अनुरोध कर सकता है?
एंटोन सैमसनोव

0

उल्लिखित मैक्रो की कोशिश करने के बाद, यह टुकड़ा वांछित परिणाम उत्पन्न करता है ( t.h):

#include <sys/cdefs.h>
#define STATIC_ASSERT(condition) typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(int) == 42);

चल रहा है cc -E t.h:

# 1 "t.h"
...
# 2 "t.h" 2

typedef char _static_assert_3[ (sizeof(int) == 4) ? 1 : -1];
typedef char _static_assert_4[ (sizeof(int) == 42) ? 1 : -1];

चल रहा है cc -o t.o t.h:

% cc -o t.o t.h
t.h:4:1: error: '_static_assert_4' declared as an array with a negative size
STATIC_ASSERT(sizeof(int) == 42);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.h:2:84: note: expanded from macro 'STATIC_ASSERT'
  ...typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
                                                       ^~~~~~~~~~~~~~~~~~~~
1 error generated.

42 सब के बाद सब कुछ का जवाब नहीं है ...


0

संकलित समय पर जांच करने के लिए कि मैंने इस तरकीब का उपयोग किया है उनकी बाधाओं के खिलाफ डेटा संरचनाओं का आकार।

#if defined(__GNUC__)
{ char c1[sizeof(x)-MAX_SIZEOF_X-1]; } // brakets limit c1's scope
#else
{ char c1[sizeof(x)-MAX_SIZEOF_X]; }   
#endif

यदि x का आकार MAX_SIZEOF_X की सीमा से अधिक या बराबर है, तो 'सरणी का आकार बहुत बड़ा है' त्रुटि के साथ gcc wil शिकायत करते हैं। VC ++ त्रुटि या तो C2148 जारी करेगा ('सरणी का कुल आकार 0x7ffffff बाइट्स से अधिक नहीं होना चाहिए' या C4266 'निरंतर आकार 0 की एक सरणी आवंटित नहीं कर सकता है'।

दो परिभाषाओं की जरूरत है क्योंकि जीसीसी इस तरह से एक शून्य-आकार के सरणी को परिभाषित करने की अनुमति देगा (आकार x - n)।


-10

sizeofऑपरेटर पूर्वप्रक्रमक के लिए उपलब्ध नहीं है, लेकिन आप स्थानांतरित कर सकते हैं sizeofसंकलक करने के लिए और क्रम में स्थिति की जांच:

#define elem_t double

#define compiler_size(x) sizeof(x)

elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
    printf("%d",(int)n);
} else {
    printf("%lf",(double)n);
}

13
पहले से ही स्वीकृत उत्तर पर यह कैसे सुधार करता है? compiler_sizeसेवा को परिभाषित करने का क्या उद्देश्य है ? आपका उदाहरण क्या दिखाने की कोशिश करता है?
बदसूरत
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.