c जयप सी कोड में ":-!!" क्या है?




भारतीय स्टेट बैंक नई दिल्ली दिल्ली (4)

मैं इस अजीब मैक्रो कोड में /usr/include/linux/kernel.h में /usr/include/linux/kernel.h :

/* Force a compilation error if condition is true, but also produce a
   result (of value 0 and type size_t), so the expression can be used
   e.g. in a structure initializer (or where-ever else comma expressions
   aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

क्या करता है :-!! कर?


यदि स्थिति गलत है, तो यह आकार 0 बिटफील्ड बना रहा है, लेकिन यदि आकार सत्य / शून्य है तो आकार -1 ( -!!1 ) बिटफील्ड। पूर्व मामले में, कोई त्रुटि नहीं है और एक int सदस्य के साथ संरचना शुरू की जाती है। बाद के मामले में, एक संकलन त्रुटि है (और निश्चित रूप से आकार -1 बिटफील्ड जैसी कोई चीज़ नहीं बनाई गई है)।


: एक बिटफील्ड है। के लिए !! , यह तार्किक दोहरी अस्वीकृति है और इसलिए गलत के लिए 0 या सत्य के लिए 1 देता है। और - एक ऋण चिह्न है, यानी अंकगणित अस्वीकृति।

अमान्य इनपुट पर कंफाइलर को बार्फ़ प्राप्त करने के लिए यह सिर्फ एक चाल है।

BUILD_BUG_ON_ZERO पर विचार करें। कब -!!(e) एक नकारात्मक मूल्य का मूल्यांकन करता है, जो एक संकलन त्रुटि उत्पन्न करता है। अन्यथा -!!(e) 0 का मूल्यांकन करता है, और 0 चौड़ाई बिटफील्ड का आकार 0 है। और इसलिए मैक्रो मूल्य 0 के साथ size_t मूल्यांकन करता है।

नाम मेरे विचार में कमजोर है क्योंकि जब इनपुट शून्य नहीं होता है तो वास्तव में निर्माण विफल हो जाता है।

BUILD_BUG_ON_NULL बहुत समान है, लेकिन एक int बजाय एक सूचक उत्पन्न करता है।


असल में, यह जांचने का एक तरीका है कि अभिव्यक्ति ई का मूल्यांकन 0 के लिए किया जा सकता है, और यदि नहीं, तो निर्माण में विफल होने के लिए

मैक्रो कुछ हद तक गलत है; यह BUILD_BUG_OR_ZERO तरह कुछ और होना चाहिए ...ON_ZERO । ( इस बारे में कभी-कभार चर्चा हुई है कि यह एक भ्रमित नाम है या नहीं ।)

आपको इस तरह की अभिव्यक्ति पढ़नी चाहिए:

sizeof(struct { int: -!!(e); }))
  1. (e) : गणना अभिव्यक्ति e

  2. !!(e) : तर्कसंगत रूप से दो बार अस्वीकार करें: 0 अगर e == 0 ; अन्यथा 1

  3. -!!(e) : चरण 2: 0 से अभिव्यक्ति को नकारात्मक रूप से अस्वीकार करें यदि यह 0 था; अन्यथा -1

  4. struct{int: -!!(0);} --> struct{int: 0;} : यदि यह शून्य थी, तो हम एक अज्ञात पूर्णांक बिटफील्ड के साथ एक संरचना घोषित करते हैं जिसमें चौड़ाई शून्य होती है। सब कुछ ठीक है और हम सामान्य के रूप में आगे बढ़ते हैं।

  5. struct{int: -!!(1);} --> struct{int: -1;} : दूसरी ओर, यदि यह शून्य नहीं है, तो यह कुछ नकारात्मक संख्या होगी। नकारात्मक चौड़ाई के साथ किसी भी बिटफील्ड को घोषित करना एक संकलन त्रुटि है।

तो हम या तो एक बिटफील्ड के साथ हवादार हो जाएंगे जिसमें संरचना में चौड़ाई 0 है, जो ठीक है, या नकारात्मक चौड़ाई वाले बिटफील्ड, जो एक संकलन त्रुटि है। फिर हम उस क्षेत्र का sizeof लेते हैं, इसलिए हमें उचित चौड़ाई के साथ size_t मिलता है (जो उस मामले में शून्य होगा जहां e शून्य है)।

कुछ लोगों ने पूछा है: क्यों न सिर्फ एक assert उपयोग करें?

केथमो का जवाब यहां एक अच्छी प्रतिक्रिया है:

ये मैक्रोज़ एक संकलन-समय परीक्षण लागू करते हैं, जबकि जोर देते हैं () एक रन-टाइम परीक्षण है।

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


कुछ लोग assert() साथ इन मैक्रोज़ को भ्रमित कर रहे हैं।

ये मैक्रोज़ एक संकलन-समय परीक्षण लागू करते assert() , जबकि assert() एक रनटाइम परीक्षण है।







linux-kernel