सभी सामान्य अपरिभाषित व्यवहार क्या हैं जिनके बारे में C ++ प्रोग्रामर को पता होना चाहिए?
कहो, जैसे:
a[i] = i++;
सभी सामान्य अपरिभाषित व्यवहार क्या हैं जिनके बारे में C ++ प्रोग्रामर को पता होना चाहिए?
कहो, जैसे:
a[i] = i++;
जवाबों:
NULL
सूचक को संदर्भित करनाmemcpy
ओवरलैपिंग बफ़र्स की प्रतिलिपि का उपयोग करना ।int64_t i = 1; i <<= 72
अपरिभाषित है)int i; i++; cout << i;
)volatile
याsig_atomic_t
सिग्नल की प्राप्ति परlong int
#if
अभिव्यक्ति में उत्पन्न करनाफ़ंक्शन मापदंडों का मूल्यांकन करने वाला क्रम अनिर्दिष्ट व्यवहार है । (यह आपके प्रोग्राम को क्रैश नहीं करेगा, विस्फोट नहीं करेगा या पिज्जा ... अपरिभाषित व्यवहार के विपरीत )।
केवल आवश्यकता यह है कि फ़ंक्शन कहा जाने से पहले सभी मापदंडों का पूरी तरह से मूल्यांकन किया जाना चाहिए।
यह:
// The simple obvious one.
callFunc(getA(),getB());
इसके बराबर हो सकता है:
int a = getA();
int b = getB();
callFunc(a,b);
या यह:
int b = getB();
int a = getA();
callFunc(a,b);
यह या तो हो सकता है; यह संकलक तक है। परिणाम दुष्प्रभाव के आधार पर मायने रख सकता है।
संकलक एक अभिव्यक्ति के मूल्यांकन भागों को फिर से आदेश देने के लिए स्वतंत्र है (अर्थ अपरिवर्तित है)।
मूल प्रश्न से:
a[i] = i++;
// This expression has three parts:
(a) a[i]
(b) i++
(c) Assign (b) to (a)
// (c) is guaranteed to happen after (a) and (b)
// But (a) and (b) can be done in either order.
// See n2521 Section 5.17
// (b) increments i but returns the original value.
// See n2521 Section 5.2.6
// Thus this expression can be written as:
int rhs = i++;
int lhs& = a[i];
lhs = rhs;
// or
int lhs& = a[i];
int rhs = i++;
lhs = rhs;
डबल चेकिंग लॉकिंग। और एक आसान गलती।
A* a = new A("plop");
// Looks simple enough.
// But this can be split into three parts.
(a) allocate Memory
(b) Call constructor
(c) Assign value to 'a'
// No problem here:
// The compiler is allowed to do this:
(a) allocate Memory
(c) Assign value to 'a'
(b) Call constructor.
// This is because the whole thing is between two sequence points.
// So what is the big deal.
// Simple Double checked lock. (I know there are many other problems with this).
if (a == null) // (Point B)
{
Lock lock(mutex);
if (a == null)
{
a = new A("Plop"); // (Point A).
}
}
a->doStuff();
// Think of this situation.
// Thread 1: Reaches point A. Executes (a)(c)
// Thread 1: Is about to do (b) and gets unscheduled.
// Thread 2: Reaches point B. It can now skip the if block
// Remember (c) has been done thus 'a' is not NULL.
// But the memory has not been initialized.
// Thread 2 now executes doStuff() on an uninitialized variable.
// The solution to this problem is to move the assignment of 'a'
// To the other side of the sequence point.
if (a == null) // (Point B)
{
Lock lock(mutex);
if (a == null)
{
A* tmp = new A("Plop"); // (Point A).
a = tmp;
}
}
a->doStuff();
// Of course there are still other problems because of C++ support for
// threads. But hopefully these are addresses in the next standard.
मेरा पसंदीदा "टेम्पलेट्स की तात्कालिकता में अनंत पुनरावृत्ति" है क्योंकि मेरा मानना है कि यह एकमात्र ऐसा स्थान है जहां संकलन समय पर अपरिभाषित व्यवहार होता है।
अपरिभाषित व्यवहार के अलावा , समान रूप से गंदा कार्यान्वयन-परिभाषित व्यवहार भी है ।
अपरिभाषित व्यवहार तब होता है जब कोई प्रोग्राम कुछ ऐसा करता है जिसका परिणाम मानक द्वारा निर्दिष्ट नहीं होता है।
कार्यान्वयन-परिभाषित व्यवहार एक कार्यक्रम द्वारा एक क्रिया है जिसका परिणाम मानक द्वारा परिभाषित नहीं किया गया है, लेकिन जिसे दस्तावेज़ में लागू करना आवश्यक है। एक उदाहरण स्टैक ओवरफ्लो प्रश्न से "मल्टीबाइट चरित्र शाब्दिक" है, क्या कोई सी संकलक है जो इसे संकलित करने में विफल रहता है? ।
कार्यान्वयन-परिभाषित व्यवहार आपको केवल तभी काटता है जब आप पोर्ट करना शुरू करते हैं (लेकिन कंपाइलर के नए संस्करण में अपग्रेड करना भी पोर्टिंग है!)।
चर केवल एक बार एक अभिव्यक्ति (तकनीकी रूप से एक बार अनुक्रम बिंदुओं के बीच) में अपडेट किए जा सकते हैं।
int i =1;
i = ++i;
// Undefined. Assignment to 'i' twice in the same expression.
विभिन्न पर्यावरणीय सीमाओं की एक बुनियादी समझ। पूरी सूची सी विनिर्देश के खंड 5.2.4.1 में है। यहाँ कुछ है;
मैं वास्तव में एक स्विच स्टेटमेंट के लिए 1023 केस लेबल की सीमा पर थोड़ा आश्चर्यचकित था, मैं समझ सकता हूं कि उत्पन्न कोड / लेक्स / पार्सर्स के लिए काफी सहजता से पार किया जा रहा है।
यदि ये सीमाएं पार हो गई हैं, तो आपके पास अपरिभाषित व्यवहार (क्रैश, सुरक्षा दोष, आदि ...) है।
सही है, मुझे पता है कि यह सी विनिर्देश से है, लेकिन सी ++ इन बुनियादी समर्थन को साझा करता है।
memcpy
अतिव्यापी मेमोरी क्षेत्रों के बीच प्रतिलिपि का उपयोग करना । उदाहरण के लिए:
char a[256] = {};
memcpy(a, a, sizeof(a));
व्यवहार C मानक के अनुसार अपरिभाषित है, जिसे C ++ 03 मानक द्वारा निर्धारित किया गया है।
सार
1 / #include void * memcpy (शून्य * प्रतिबंधित s1, const void * प्रतिबंधित s2, size_n n);
विवरण
2 / memcpy फ़ंक्शन s1 द्वारा इंगित ऑब्जेक्ट में s2 द्वारा इंगित ऑब्जेक्ट से n वर्णों की प्रतिलिपि बनाता है। यदि ओवरलैप करने वाली वस्तुओं के बीच नकल होती है, तो व्यवहार अपरिभाषित है। रिटर्न 3 मेमॉपी फ़ंक्शन s1 का मान लौटाता है।
सार
1 #include void * memmove (void * s1, const void * s2, size_t n);
विवरण
2 मेमोव फ़ंक्शन एन 1 द्वारा इंगित ऑब्जेक्ट में s2 द्वारा बताई गई वस्तु से n वर्णों की प्रतिलिपि बनाता है। नकल करना ऐसा लगता है मानो s2 द्वारा बताई गई वस्तु से n वर्ण पहले n वर्णों के एक अस्थायी सरणी में कॉपी किए गए हैं जो s1 और s2 द्वारा इंगित की गई वस्तुओं को ओवरलैप नहीं करते हैं, और फिर अस्थायी सरणी से n वर्णों की प्रतिलिपि बनाई जाती है s1 द्वारा इंगित की गई वस्तु। रिटर्न
3 मेमोव फ़ंक्शन s1 का मान लौटाता है।
एकमात्र प्रकार जिसके लिए C ++ एक आकार की गारंटी देता है char
। और आकार 1. अन्य सभी प्रकारों का आकार प्लेटफॉर्म पर निर्भर है।