C ++ 98 ve C ++ 03
Bu yanıt C ++ standardının eski sürümleri içindir. Standardın C ++ 11 ve C ++ 14 sürümleri resmi olarak 'dizi noktaları' içermez; operasyonlar 'önce sıralanır' veya 'sıralanmamış' veya 'belirsiz şekilde sıralanır'. Net etki esasen aynıdır, ancak terminoloji farklıdır.
Feragatname : Tamam. Bu cevap biraz uzun. Okurken sabırlı olun. Bunları zaten biliyorsanız, tekrar okumak sizi delirtmeyecektir.
Önkoşul : Temel C ++ Standardı bilgisi
Dizi Noktaları nedir?
Standart diyor
Yürütme sekansında sekans noktaları adı verilen belirli belirtilen noktalarda , önceki değerlendirmelerin tüm yan etkileri tamamlanmış olacak ve sonraki değerlendirmelerin hiçbir yan etkisi gerçekleşmeyecektir. (/ 7 §1.9)
Yan etkiler? Yan etkileri nelerdir?
Bir ifadenin değerlendirilmesi bir şey üretir ve ek olarak yürütme ortamının durumunda bir değişiklik varsa, ifadenin (değerlendirmesinin) bazı yan etkileri olduğu söylenir.
Örneğin:
int x = y++; //where y is also an int
Başlatma işlemine ek olarak, operatörün y
yan etkisi nedeniyle değeri değişir ++
.
Çok uzak çok iyi. Sıralama noktalarına geçilir. Comp.lang.c yazarı tarafından verilen seq-noktalarının alternatif bir tanımı Steve Summit
:
Sekans noktası, tozun çöktüğü ve şimdiye kadar görülen tüm yan etkilerin tamamlandığı garanti edilen bir noktadır.
C ++ Standardında listelenen ortak sıra noktaları nelerdir?
Onlar:
tam ifadenin değerlendirilmesinin sonunda ( §1.9/16
) (Tam ifade, başka bir ifadenin alt ifadesi olmayan bir ifadedir.) 1
Misal :
int a = 5; // ; is a sequence point here
ilk ifadenin değerlendirilmesinden sonra aşağıdaki ifadelerin her birinin değerlendirilmesinde ( §1.9/18
) 2
a && b (§5.14)
a || b (§5.15)
a ? b : c (§5.16)
a , b (§5.18)
(burada a, b virgül operatörüdür; virgül operatörü func(a,a++)
,
değildir, yalnızca argümanlar a
ve arasında bir ayırıcıdır a++
. Dolayısıyla, bu durumda davranış tanımsızdır (eğer a
ilkel bir tür olarak kabul edilirse )
Bir işlev çağrısında (işlev satır içi olsun veya olmasın), işlev gövdesinde ( §1.9/17
) ifadeler veya ifadelerin yürütülmesinden önce gerçekleşen tüm işlev bağımsız değişkenlerinin (varsa) değerlendirilmesinden sonra .
1: Not: bir tam ifadenin değerlendirilmesi, tam ifadenin sözlüksel olarak bir parçası olmayan alt ifadelerin değerlendirilmesini içerebilir. Örneğin, varsayılan bağımsız değişken ifadelerinin (8.3.6) değerlendirilmesinde yer alan alt ifadelerin, varsayılan bağımsız değişkeni tanımlayan ifadede değil, işlevi çağıran ifadede oluşturulduğu kabul edilir
2: Belirtilen işleçler, 5. maddede açıklandığı gibi yerleşik işleçlerdir. Bu işleçlerden biri geçerli bir bağlamda aşırı yüklendiğinde (madde 13), böylece kullanıcı tanımlı bir işleç işlevi belirlendiğinde, ifade bir işlev çağırma ve işlenenler, aralarında zımni bir sıra noktası bulunmayan bir argüman listesi oluşturur.
Tanımsız Davranış Nedir?
Standart Bölüm Tanımsız davranışı tanımlar §1.3.12
olarak
davranış, bu standard yüklediği kendisi için hatalı bir program yapısının veya hatalı veriler, kullanımı üzerine ortaya çıkabilecek gibi hiçbir gereksinimleri 3 .
Bu Uluslararası Standart, herhangi bir açık davranış tanımının açıklamasını atladığında tanımlanmamış davranışlar da beklenebilir.
3: izin verilen tanımlanamayan davranış, durumu tamamen öngörülemeyen sonuçlarla görmezden gelmekten, çeviri veya program yürütme sırasında ortamın karakteristik bir şekilde (bir tanılama iletisinin verilmesiyle veya verilmesiyle), bir çeviri veya yürütmenin sona erdirilmesine kadar değişir. (bir teşhis mesajı verilmesi ile).
Kısacası, tanımsız davranış , burnunuzdan uçan cinlerden kız arkadaşınıza hamile kalmaya kadar her şeyin olabileceği anlamına gelir .
Tanımsız Davranış ve Sıra Noktaları arasındaki ilişki nedir?
Buna girmeden önce Tanımsız Davranış, Belirsiz Davranış ve Uygulama Tanımlı Davranış arasındaki farkları bilmelisiniz .
Bunu da bilmelisin the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified
.
Örneğin:
int x = 5, y = 6;
int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.
Burada başka bir örnek .
Şimdi Standart §5/4
diyor ki
- 1) Önceki ve sonraki dizi noktası arasında, bir skaler nesne, bir ifadenin değerlendirilmesi ile depolanmış değerinin en fazla bir kez değiştirilmiş olması gerekir.
Bunun anlamı ne?
Gayri resmi olarak, iki dizi noktası arasında bir değişkenin birden fazla değiştirilmemesi gerektiği anlamına gelir. Bir ifade ifadesinde, next sequence point
genellikle sonlandırma noktalı virgülünde ve previous sequence point
önceki ifadenin sonundadır. Bir ifade ara madde de içerebilir sequence points
.
Yukarıdaki cümleden aşağıdaki ifadeler Tanımsız Davranışı çağırır:
i++ * ++i; // UB, i is modified more than once btw two SPs
i = ++i; // UB, same as above
++i = 2; // UB, same as above
i = ++i + 1; // UB, same as above
++++++i; // UB, parsed as (++(++(++i)))
i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)
Ancak aşağıdaki ifadeler iyidir:
i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i); // well defined
int j = i;
j = (++i, i++, j*i); // well defined
- 2) Ayrıca, önceki değere sadece depolanacak değerin belirlenmesi için erişilebilir.
Bunun anlamı ne? Bu, bir nesnenin tam bir ifade içinde yazılması durumunda, aynı ifade içindeki herhangi bir erişimin ve tüm erişimlerin, yazılacak değerin hesaplanmasında doğrudan yer alması gerektiği anlamına gelir .
Örneğin (LHS ve RHS'de) i = i + 1
tüm erişim, yazılacak değerin hesaplanmasında doğrudan yer alır . Yani iyi.i
Bu kural, yasal ifadeleri, erişimin modifikasyondan açıkça önce geçtiği ifadelerle etkili bir şekilde kısıtlar.
Örnek 1:
std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2
Örnek 2:
a[i] = i++ // or a[++i] = i or a[i++] = ++i etc
izin verilmez, çünkü i
(içinde olanın a[i]
) erişimlerinden birinin i'de depolanan değerle ilgisi yoktur (içinde gerçekleşir i++
) ve bu yüzden tanımlamak için iyi bir yol yoktur - ya bizim anlayışımız için ya da derleyicinin - erişimin, artan değerin kaydedilmesinden önce veya sonra gerçekleşip gerçekleşmeyeceği. Yani davranış tanımsız.
Örnek 3:
int x = i + i++ ;// Similar to above
Burada C ++ 11 için cevap izleyin .
*p++ = 4
Tanımsız Davranış değildir.*p++
olarak yorumlanır*(p++)
.p++
döndürürp
(bir kopya) ve önceki adreste saklanan değeri döndürür . Neden UB'yi çağırsın ki? Mükemmel para cezası.