C मानक को मशीन के पते पर शून्य बिंदुओं की आवश्यकता नहीं होती है। कैसे, 0
एक पॉइंटर पॉइंटर को स्थिर रखने से एक पॉइंटर NULL
(VER6.3.2.3 / 3) में परिणाम होना चाहिए , और बूलियन के रूप में अशक्त पॉइंटर का मूल्यांकन करना गलत होना चाहिए। इसमें कुछ समय अजीब यदि आप वास्तव में हो सकता है है एक शून्य पता चाहते हैं, और NULL
शून्य का पता नहीं है।
फिर भी, (भारी) संकलक और मानक पुस्तकालय में संशोधन के NULL
साथ, एक वैकल्पिक बिट पैटर्न के साथ प्रतिनिधित्व किया जाना असंभव नहीं है, जबकि अभी भी मानक पुस्तकालय के सख्ती से अनुरूप हैं। यह केवल स्वयं की परिभाषा को बदलने के लिए पर्याप्त नहीं हैNULL
, लेकिन तब NULL
यह सच का मूल्यांकन करेगा।
विशेष रूप से, आपको निम्न की आवश्यकता होगी:
- असाइनमेंट टू पॉइंटर्स (या कास्ट टू पॉइंटर्स) को शाब्दिक शून्य में व्यवस्थित करने के लिए कुछ अन्य जादुई मूल्य में परिवर्तित किया जा सकता है
-1
।
0
इसके बजाय मैजिक वैल्यू की जांच के लिए पॉइंटर्स और एक स्थिर पूर्णांक के बीच समानता परीक्षणों की व्यवस्था करें (tests6.5.9 / 6)
- सभी संदर्भों के लिए व्यवस्थित करें, जिसमें एक सूचक प्रकार का मूल्यांकन बूलियन के रूप में किया जाता है ताकि शून्य के लिए जाँच करने के बजाय जादू मूल्य के लिए समानता की जांच की जा सके। यह समानता परीक्षण शब्दार्थ से आता है, लेकिन संकलक इसे आंतरिक रूप से अलग तरह से लागू कर सकता है। See6.5.13 / 3, .16.5.14 / 3, .16.5.15 / 4, /6.5.3.3 / 5, §6.8.4.1 / 2, §6.8.5 / 4 देखें
- जैसा कि बताया गया है, नए शून्य सूचक प्रतिनिधित्व को दर्शाने के लिए स्थैतिक वस्तुओं (.76.7.8 / 10) और आंशिक यौगिक आरंभीकरण (initial6.7.8 / 21) के आरंभीकरण के लिए शब्दार्थ को अद्यतन करें।
- सत्य पता शून्य तक पहुँचने का एक वैकल्पिक तरीका बनाएँ।
कुछ चीजें हैं जिन्हें आपको संभालना नहीं है। उदाहरण के लिए:
int x = 0;
void *p = (void*)x;
इसके बाद, p
एक शून्य सूचक होने की गारंटी नहीं है। केवल निरंतर असाइनमेंट को संभालने की जरूरत है (यह सही पता शून्य तक पहुंचने के लिए एक अच्छा तरीका है)। इसी तरह:
int x = 0;
assert(x == (void*)0); // CAN BE FALSE
इसके अलावा:
void *p = NULL;
int x = (int)p;
x
होने की गारंटी नहीं है 0
।
संक्षेप में, इस स्थिति को सी भाषा समिति द्वारा स्पष्ट रूप से माना गया था, और उन लोगों के लिए विचार किया गया था जो NULL के लिए एक वैकल्पिक प्रतिनिधित्व का चयन करेंगे। अब आपको बस इतना करना है कि अपने कंपाइलर में बड़े बदलाव करें, और हे प्रीस्टो आप कर रहे हैं :)
एक साइड नोट के रूप में, कंपाइलर उचित से पहले एक स्रोत कोड परिवर्तन चरण के साथ इन परिवर्तनों को लागू करना संभव हो सकता है। यह है कि प्रीप्रोसेसर के सामान्य प्रवाह के बजाय -> संकलक -> कोडांतरक -> लिंकर, आप एक पूर्वप्रक्रमक जोड़ेंगे -> पूर्ण परिवर्तन -> संकलक -> कोडांतरक -> लिंकर। तब आप परिवर्तन कर सकते हैं जैसे:
p = 0;
if (p) { ... }
/* becomes */
p = (void*)-1;
if ((void*)(p) != (void*)(-1)) { ... }
इसके लिए एक पूर्ण सी पार्सर की आवश्यकता होती है, साथ ही एक प्रकार के पार्सर और टाइपराइफ और चर घोषणाओं के विश्लेषण से यह निर्धारित होता है कि पहचानकर्ता बिंदुओं के अनुरूप हैं। हालाँकि, ऐसा करने से आप कंपाइलर के कोड जनरेशन पोर्ट में बदलाव करने से बच सकते हैं।इसे लागू करने के लिए क्लैंग उपयोगी हो सकता है - मैं समझता हूं कि इसे इस तरह के परिवर्तनों के साथ डिजाइन किया गया था। आपको अभी भी निश्चित रूप से मानक पुस्तकालय में बदलाव करने की आवश्यकता होगी।
mprotect
सुरक्षित कर सकते हैं । या, यदि प्लेटफ़ॉर्म में कोई ASLR या जैसा नहीं है, तो प्लेटफ़ॉर्म भौतिक मेमोरी से परे पते। सौभाग्य।