(Neden) başlatılmamış değişken tanımsız davranış kullanıyor?


82

Sahip olursam:

bu ifadeden sonra sıfır olması x gerektiği açıktır , ancak baktığım her yerde , bu kodun davranışının tanımsız olduğunu söylüyorlar, sadece değerinin değil x(çıkarma öncesine kadar).

İki soru:

  • Is davranış bu kodun gerçekten tanımsız?
    (Örneğin, uyumlu bir sistemde kod çökebilir mi [veya daha kötüsü]?)

  • Öyleyse, burada sıfır olması gerektiği tamamen açıkken C neden davranışın tanımsız olduğunu söylüyor x?

    Yani burada davranışı tanımlamamanın sağladığı avantaj nedir ?

Açıkça, derleyici değişken içinde "kullanışlı" olarak gördüğü her türlü çöp değerini kullanabilir ve amaçlandığı gibi çalışacaktır ... Bu yaklaşımın nesi yanlış?



3
Buradaki davranış için özel bir durum tanımlamanın sağladığı avantaj nedir? Elbette, hepimiz programlarımızı ve kitaplıklarımızı daha büyük ve daha yavaş yapalım çünkü @Mehrdad bir değişkeni belirli ve nadir bir durumda başlatmaktan kaçınmak istiyor.
Paul Tomblin

9
@ W'rkncacnter Bunun bir dupe olduğuna katılmıyorum. Hangi değerin alındığına bakılmaksızın, OP bunun sıfır olmasını bekler x -= x. Soru, başlatılmamış değerlere erişmenin neden UB olduğudur.
Mysticial

6
İlginçtir ki x = 0; genellikle montajda xor x, x'e dönüştürülür. Neredeyse burada yapmaya çalıştığınız şeyle aynı, ancak çıkarma yerine xor ile.
0xFE

1
Yani burada davranışı tanımlamamanın getirdiği avantaj nedir? '- Bir veya daha fazla değişkene bağlı olmayan değerlerle ifadelerin sonsuzluğunu listelemeyen standardın avantajının açık olduğunu düşünürdüm. Aynı zamanda @Paul, standartta böyle bir değişiklik, programları ve kitaplıkları daha da büyütmeyecektir.
Jim Balter

Yanıtlar:


90

Evet, bu davranış tanımlanmamıştır, ancak çoğu insanın bildiğinden farklı nedenlerle.

Birincisi, birimselleştirilmiş bir değer kullanmak kendi başına tanımsız bir davranış değildir, ancak değer belirsizdir. Değer, tür için bir tuzak temsili olursa, buna erişim UB'dir. İmzasız türlerin nadiren tuzak temsilleri vardır, bu nedenle o tarafta nispeten güvende olursunuz.

Davranışı tanımsız yapan, değişkeninizin ek bir özelliğidir, yani "ile bildirilmiş olabilir", yani registeradresi asla alınmaz. Bu tür değişkenler özel olarak ele alınır, çünkü "başlatılmamış" olan ve tür etki alanındaki bir değere karşılık gelmeyen bir tür ekstra duruma sahip olan gerçek CPU kayıtlarına sahip mimariler vardır.

Düzenleme: Standardın ilgili ifadesi 6.3.2.1p2'dir:

Lvalue, kayıt saklama sınıfıyla bildirilebilecek otomatik depolama süresi olan bir nesneyi belirtirse (adresi asla alınmamışsa) ve bu nesne başlatılmamışsa (bir başlatıcı ile bildirilmez ve kullanımdan önce ona atama yapılmamışsa) ), davranış tanımsızdır.

Ve daha anlaşılabilir olması için, aşağıdaki kod olan her koşulda yasal:

  • İşte adresleri ave bonların değeri sadece belirsiz yüzden alınır.
  • Yana unsigned chartuzak temsillerini vardır asla belirsiz değer herhangi bir değer, sadece belirtilmemiş olduğunu unsigned chargerçekleşebilir.
  • Sonunda a gerekir değerini tutun 0.

Edit2: a ve bbelirtilmemiş değerlere sahip:

3.19.3 belirtilmemiş değer
Bu Uluslararası Standardın herhangi bir durumda seçildiği değerle ilgili herhangi bir şart getirmediği durumlarda ilgili türün geçerli değeri


6
Belki bir şeyi kaçırıyorum, ama bana öyle geliyor ki, bu unsignedkesinlikle tuzak temsillerine sahip olabilir. Standardın böyle söyleyen kısmına işaret edebilir misiniz? §6.2.6.2 / 1'de aşağıdakileri görüyorum: " İşaretsiz karakter dışındaki işaretsiz tamsayı türleri için, nesne temsilinin bitleri iki gruba bölünecektir: değer bitleri ve doldurma bitleri (sonuncularından herhangi biri gerekli değildir). ... bu değer temsili olarak bilinmelidir. Herhangi bir doldurma bitinin değerleri belirtilmemiştir. ⁴⁴⁾ "yorumla birlikte:" ⁴⁴⁾ Bazı dolgu bitleri kombinasyonları tuzak gösterimleri oluşturabilir ".
conio

6
Yorumun devamı: "Bazı doldurma bitleri kombinasyonları, örneğin, eğer bir dolgu biti bir eşlik bitiyse, tuzak gösterimleri oluşturabilir. Ne olursa olsun, geçerli değerler üzerinde hiçbir aritmetik işlem, aşağıdaki gibi istisnai bir koşulun parçası olmaktan başka bir tuzak gösterimi oluşturamaz. bir taşma ve bu işaretsiz türlerde gerçekleşemez. " - Bu harika bir kez biz çalışmak için geçerli bir değere sahip, ancak belirsiz değer olabilir (örn eşlik biti set yanlış) başlatıldı önce bir tuzak gösterimi ol.
conio

4
@conio dışındaki tüm türler için haklısınız unsigned char, ancak bu yanıt kullanılıyor unsigned char. Bununla birlikte, kesin olarak uyumlu bir program hesaplayabilir sizeof(unsigned) * CHAR_BITve UINT_MAXbelirli uygulamaların tuzak temsillerine sahip olamayacağına bağlı olarak belirleyebilir unsigned. Program bu belirlemeyi yaptıktan sonra, bu cevabın ne yaptığını tam olarak yapmaya devam edebilir unsigned char.

4
@JensGustedt: Bu memcpybir dikkat dağıtıcı değil mi , yani örneğiniz ile değiştirilseydi hala geçerli olmazdı *&a = *&b;.
R .. GitHub ICE YARDIMINI DURDUR

4
@R .. Artık emin değilim. C komitesinin posta listesinde devam eden bir tartışma var ve görünüşe göre tüm bunlar büyük bir karmaşa, yani amaçlanan (veya yapılan) davranış ile gerçekte yazılanlar arasında büyük bir boşluk. Yine de açık olan şey, belleğe erişmenin unsigned charve dolayısıyla memcpyyardımcı olmanın, bunun için olanın *&daha az açık olmasıdır. Bu yerleştiğinde rapor edeceğim.
Jens Gustedt

24

C standardı, derleyicilere optimizasyonları gerçekleştirmek için çok fazla serbestlik sağlar. Başlatılmamış belleğin rastgele bir bit modeline ayarlandığı ve tüm işlemlerin yazıldıkları sırada gerçekleştirildiği saf bir program modelini varsayarsanız, bu optimizasyonların sonuçları şaşırtıcı olabilir.

Not: Aşağıdaki örnekler sadece xadresi hiçbir zaman alınmadığı için geçerlidir , bu yüzden "kayıt benzeri" dir. xTuzak temsillerinin türünün olması durumunda da geçerli olacaktır ; Bu, imzasız türler için nadiren söz konusudur (en az bir bit depolama alanını “boşa harcamayı” gerektirir ve belgelenmelidir) ve bunun için imkansızdır unsigned char. Eğer x(2 - imzalanmış türü oldu ve ardından uygulama, bir sayı arasında değil bit modelini tanımlayabilir n-1 1) ve 2 N-1 -1 tuzak temsili olarak. Jens Gustedt'in cevabına bakın .

Derleyiciler değişkenlere yazmaç atamaya çalışır, çünkü yazmaçlar bellekten daha hızlıdır. Program, işlemcinin yazmaçlarına göre daha fazla değişken kullanabileceğinden, derleyiciler, farklı zamanlarda aynı kaydı kullanan farklı değişkenlere yol açan kayıt tahsisi gerçekleştirir. Program parçasını düşünün

3. satır değerlendirildiğinde, xhenüz başlatılmamıştır, bu nedenle (derleyicinin nedenleri) 3. satır, derleyicinin anlayacak kadar akıllı olmadığı diğer koşullar nedeniyle gerçekleşemeyen bir tür tesadüf olmalıdır. Yana zhattı 4 sonra kullanılmaz ve xhat 5 önce kullanılmaz, aynı kayıt iki değişken için kullanılabilir. Dolayısıyla bu küçük program, kayıtlar üzerinde aşağıdaki işlemlere göre derlenmiştir:

Nihai değeri x, nihai değeridir r0ve nihai değeri y, nihai değeridir r1. Bu değerler x = -3 ve y = -4'tür ve xuygun şekilde başlatılmış olsaydı olacağı gibi 5 ve 4 değildir .

Daha ayrıntılı bir örnek için aşağıdaki kod parçasını göz önünde bulundurun:

Derleyicinin conditionhiçbir yan etkisi olmadığını algıladığını varsayalım . Değişiklik conditionyapmadığından x, derleyici döngü boyunca ilk çalıştırmanın xhenüz başlatılmadığı için erişilemeyeceğini bilir . Bu nedenle, döngü gövdesinin ilk çalıştırılması x = some_value()koşulu test etmeye gerek yoktur. Derleyici bu kodu sizin yazmışsınız gibi derleyebilir

Bu derleyici iç modellenmiş olabilir yolu bağlı herhangi bir değer olduğunu dikkate almaktır xsahiptir uygun olduğu herhangi bir değer uzun olarak xbaşlatılmamış olması. İlklendirilmemiş bir değişkenin davranışı tanımsız olduğundan, değişkenin sadece tanımlanmamış bir değere sahip olması yerine, derleyicinin uygun olan değerler arasındaki herhangi bir özel matematiksel ilişkiyi takip etmesi gerekmez. Böylece derleyici yukarıdaki kodu şu şekilde analiz edebilir:

  • ilk döngü yinelemesi sırasında, xzaman -xdeğerlendirildiğinde başlatılmamış olur.
  • -x tanımsız bir davranışa sahiptir, dolayısıyla değeri uygun olanıdır.
  • Optimizasyon kuralı geçerlidir, bu nedenle bu kod basitleştirilebilir .condition ? value : valuecondition; value

Sorunuzdaki kodla karşılaşıldığında, aynı derleyici x = - x, değerlendirildiğinde değerinin uygun olanı -xolduğunu analiz eder . Böylece atama optimize edilebilir.

Yukarıda açıklandığı gibi davranan bir derleyici örneği aramadım, ancak bu iyi derleyicilerin yapmaya çalıştığı optimizasyon türleridir. Biriyle karşılaşmak beni şaşırtmaz. İşte programınızın çöktüğü daha az makul bir derleyici örneği. (Programınızı bir tür gelişmiş hata ayıklama modunda derlerseniz bu mantıksız olmayabilir.)

Bu varsayımsal derleyici, farklı bir bellek sayfasındaki her değişkeni eşler ve sayfa özniteliklerini ayarlar, böylece başlatılmamış bir değişkenden okuma, bir hata ayıklayıcıyı çağıran bir işlemci tuzağına neden olur. Bir değişkene yapılan herhangi bir atama, önce onun bellek sayfasının normal şekilde eşleştirilmesini sağlar. Bu derleyici herhangi bir gelişmiş optimizasyon gerçekleştirmeye çalışmaz - başlatılmamış değişkenler gibi hataları kolayca bulmayı amaçlayan bir hata ayıklama modundadır. Ne zaman x = - xdeğerlendirilir, sağ taraftaki bir tuzak neden olur ve ayıklayıcı kadar ateşler.


+1 Güzel açıklama, standart bu duruma özel bir özen gösteriyor. Bu hikayenin devamı için aşağıdaki cevabıma bakın. (yorum yapmak için çok uzun).
Jens Gustedt

@JensGustedt Oh, cevabınız benim (ve diğerlerinin) gözden kaçırdığı çok önemli bir noktaya işaret ediyor: tipte, işaretsiz bir tip için en az bir bit "israf" gerektiren tuzak değerleri yoksa, xbaşlatılmamış bir değere sahipse, ancak erişimdeki davranış x kayıt benzeri davranışa sahip değilse tanımlanabilir.
Gilles 'SO- kötü olmayı bırak'

@Gilles: en azından clang, bahsettiğiniz optimizasyonları yapar: (1) , (2) , (3) .
Vlad

1
Bu tarzda clang işlem şeylerine sahip olmanın pratik avantajı nedir? Eğer aşağı akış kodu hiçbir zaman değerini kullanmazsa, değeri xtanımlanmış olsun ya da olmasın üzerindeki tüm işlemler atlanabilir. Örneğin aşağıdaki kod , sıfır vermiş olduğu durumda içerebilecek if (volatile1) x=volatile2; ... x = (x+volatile3) & 255;herhangi bir 0-255 değerinden eşit derecede memnun olacaksa , programcının gereksiz bir yazmayı atlamasına izin verecek bir uygulamanın, daha yüksek kaliteli olarak kabul edilmesi gerektiğini düşünürdüm. davranırdı ...xvolatile1x
supercat

... bu durumda tamamen tahmin edilemez bir şekilde. Bu durumda, uygulama tanımlı bir tuzağı güvenilir bir şekilde ortaya çıkaracak bir uygulama, belirli amaçlar için, daha yüksek kalitede olarak kabul edilebilir, ancak tamamen öngörülemez şekilde davranmak, bana hemen hemen her amaç için en düşük kaliteli davranış biçimi gibi görünmektedir.
supercat

16

Evet, program çökebilir. Örneğin, işlenmeyen bir CPU kesintisine neden olabilecek ve programı çökertebilecek tuzak gösterimleri (ele alınamayan belirli bit desenleri) olabilir.

(6.2.6.1, geç bir C11 taslağında diyor ki) Belirli nesne temsillerinin, nesne türünün bir değerini temsil etmesi gerekmez. Bir nesnenin depolanan değeri böyle bir temsile sahipse ve karakter türü olmayan bir lvalue ifadesi tarafından okunursa, davranış tanımsızdır. Böyle bir temsil, karakter tipine sahip olmayan bir lvalue ifadesi tarafından nesnenin tamamını veya herhangi bir bölümünü değiştiren bir yan etki tarafından üretilirse, davranış tanımsızdır. 50) Böyle bir temsil, tuzak gösterimi olarak adlandırılır.

(Bu açıklama, yalnızca unsigned intgerçek dünya sistemlerinde nadir görülen tuzak temsillerine sahip olabilen platformlar için geçerlidir ; standardın mevcut ifadesine yol açan alternatif ve belki de daha yaygın nedenlere yönelik ayrıntılar ve yönlendirmeler için yorumlara bakın.)


3
@VladLazarenko: Bu C ile ilgili, belirli CPU'lar değil. Herkes onu çılgına çeviren tamsayılar için bit desenleri olan bir CPU tasarlayabilir. Kayıtlarında "çılgın bit" olan bir CPU düşünün.
David Schwartz

2
Öyleyse tamsayılar ve x86 durumunda davranışın iyi tanımlandığını söyleyebilir miyim?

3
Teorik olarak, yalnızca 28 bitlik tamsayılar (x86'da) kullanmaya karar veren ve her toplama, çarpma işlemini (ve benzeri) işlemek için belirli bir kod ekleyen ve bu 4 bitin kullanılmamasını sağlayan (veya aksi takdirde bir SIGSEGV gönderen bir derleyiciniz olabilir ). Değersiz bir değer buna neden olabilir.
eq-

4
Birinin konuyu anlamadığı için herkese hakaret etmesinden nefret ediyorum. Davranışın tanımsız olup olmadığı tamamen standardın ne söylediğine bağlıdır. Oh, ve eq'in senaryosuyla ilgili hiçbir pratik şey yok ... tamamen uydurma.
Jim Balter

7
@Vlad Lazarenko: Itanium CPU'larında her tamsayı kaydı için bir NaT (Not a Thing) bayrağı vardır. NaT Bayrağı, spekülatif yürütmeyi kontrol etmek için kullanılır ve kullanımdan önce uygun şekilde başlatılmamış yazmaçlarda kalabilir. NaT bit setiyle böyle bir kayıttan okumak bir istisnaya neden olur. Bkz blogs.msdn.com/b/oldnewthing/archive/2004/01/19/60162.aspx
İskandinav Ana Bilgisayara

13

(Bu cevap C 1999'a hitap etmektedir. C 2011 için Jens Gustedt'in cevabına bakınız.)

C standardı, başlatılmamış otomatik depolama süresi olan bir nesnenin değerini kullanmanın tanımsız bir davranış olduğunu söylemez. C 1999 standardı 6.7.8 10'da "Otomatik depolama süresi olan bir nesne açıkça başlatılmazsa değeri belirsizdir" der. (Bu paragraf statik nesnelerin nasıl başlatıldığını tanımlamaya devam eder, bu nedenle ilgilendiğimiz tek başlatılmamış nesneler otomatik nesnelerdir.)

3.17.2 "belirsiz değeri" "belirtilmemiş bir değer veya bir tuzak temsili" olarak tanımlar. 3.17.3, "belirlenmemiş değeri", "bu Uluslararası Standardın herhangi bir durumda seçildiği değerle ilgili hiçbir şart getirmediği durumlarda ilgili türün geçerli değeri" olarak tanımlar.

Dolayısıyla, başlatılmamış unsigned int xbir değere sahipse, x -= xsıfır üretmelidir. Bu bir tuzak temsili olup olmadığı sorusunu bırakıyor. Bir tuzak değerine erişim, 6.2.6.1 uyarınca tanımlanmamış davranışa neden olur 5.

Bazı nesne türleri, kayan noktalı sayıların NaN'leri gibi tuzak temsillerine sahip olabilir. Ancak işaretsiz tamsayılar özeldir. 6.2.6.2'ye göre, işaretsiz bir int'in N değer bitlerinin her biri 2'nin gücünü temsil eder ve değer bitlerinin her bir kombinasyonu, 0 ila 2 N- 1 arasındaki değerlerden birini temsil eder . Bu nedenle, işaretsiz tamsayılar, yalnızca dolgu bitlerindeki bazı değerler (eşlik biti gibi) nedeniyle tuzak temsillerine sahip olabilir.

Hedef platformunuzda, işaretsiz bir int doldurma bitine sahip değilse, o zaman başlatılmamış bir işaretsiz int bir tuzak temsiline sahip olamaz ve değerini kullanmak tanımsız davranışa neden olamaz.


xTuzak temsili varsa , tuzak x -= xolabilir, değil mi? Yine de, fazladan bit içermeyen işaretsiz tamsayıları işaret eden +1, tanımlanmış bir davranışa sahip olmalıdır - açıkça diğer yanıtların tam tersidir ve (alıntıya göre), standardın ima ettiği gibi görünüyor.
user541686

Evet, türün xbir tuzak temsili varsa, o zaman x -= xtuzak olabilir. Basitçe xbir değer olarak kullanıldığında bile tuzağa düşebilir. (Bir değer olarak kullanmak güvenlidir x; bir nesneye yazmak, içindeki tuzak temsilinden etkilenmez.)
Eric Postpischil

imzasız türlerde nadiren tuzak temsili bulunur
Jens Gustedt

Aktaran Raymond Chen , "ia64, her 64 bit register aslında 65 bittir. Ekstra bit denir‘bir şey olmaz ‘’ açılımı’Nat. Yazmaç geçerli bir değer içermiyorsa biti ayarlanır. Bunu, kayan nokta NaN'nin tamsayı versiyonu olarak düşünün. ... eğer değeri NaT olan bir sicil kaydınız varsa ve onu yanlış bir şekilde soluyorsanız (örneğin, değerini belleğe kaydetmeye çalışın), işlemci bir STATUS_REG_NAT_CONSUMPTION istisnası oluşturacak ". Yani, bir tuzak biti değerin tamamen dışında olabilir.
Şerefe ve hth. - Alf

−1 "Hedef platformunuzda, işaretsiz bir int doldurma biti yoksa, o zaman başlatılmamış bir işaretsiz int bir tuzak temsiline sahip olamaz ve değerini kullanmak tanımsız davranışa neden olamaz." x64 NaT bitleri gibi şemaları dikkate almıyor.
Şerefe ve hth. - Alf

11

Evet, tanımsız. Kod çökebilir. C, davranışın tanımsız olduğunu çünkü genel kurala bir istisna yapmak için belirli bir neden olmadığını söylüyor. Avantaj, diğer tüm tanımsız davranış durumlarıyla aynı avantajdır - derleyicinin bunun çalışması için özel kod üretmesi gerekmez.

Açıkçası, derleyici değişken içinde "kullanışlı" olarak gördüğü her türlü çöp değerini kullanabilir ve amaçlandığı gibi çalışacaktır ... Bu yaklaşımın nesi yanlış?

Bunun neden olmadığını düşünüyorsun? Bu tam olarak alınan yaklaşım. Derleyicinin onu çalıştırması gerekmez, ancak başarısız olması gerekmez.


1
Derleyicinin bunun için de özel bir koda sahip olması gerekmez. Basitçe alanı ayrılıyor (her zaman olduğu gibi) ve değil intializing değişkeni o doğru davranış verir. Bunun özel bir mantık gerektirdiğini sanmıyorum.
user541686

7
1) Elbette olabilirler. Ama bunu daha iyi hale getirecek herhangi bir iddia düşünemiyorum. 2) Platform, başlatılmamış belleğin değerine güvenilemeyeceğini bilir, bu nedenle değiştirmekte özgürdür. Örneğin, gerektiğinde kullanıma hazır sıfırlanmış sayfalara sahip olmak için arka planda başlatılmamış belleği sıfırlayabilir. (Bu olursa: 1) Çıkarılacak değeri okuyoruz, diyelim ki 3 alıyoruz. 2) Sayfa sıfırlanıyor çünkü değeri 0 olarak değiştiriyoruz. 3) Atomik bir çıkarma yapıyoruz, sayfayı tahsis ediyoruz ve değer -3. Oops.)
David Schwartz

2
-1 çünkü iddianız için hiçbir gerekçe sunmuyorsunuz. Derleyicinin sadece bellek konumuna yazılan değeri almasını beklemenin geçerli olacağı durumlar vardır.
Jens Gustedt

1
@JensGustedt: Yorumunuzu anlamıyorum. Lütfen açıklar mısın?
David Schwartz

3
Çünkü ona atıfta bulunmadan genel bir kural olduğunu iddia ediyorsunuz. Bu nedenle, SO'da beklediğim gibi olmayan bir "otorite ile kanıtlama" girişimidir. Ve bunun neden belirsiz bir değer olamayacağını etkili bir şekilde tartışmadığın için. Genel durumda bunun UB olmasının tek nedeni, xolarak ilan edilebilecek registerolması, yani adresinin asla alınmamasıdır. Bunun farkında mısın bilmiyorum (eğer, etkili bir şekilde saklıyorsan) ama doğru bir cevap bundan bahsetmeli.
Jens Gustedt

7

Herhangi bir türdeki herhangi bir değişken için, başlatılmamış veya başka nedenlerle belirsiz bir değer tutarsa, bu değeri okuyan kod için aşağıdakiler geçerlidir:

  • Değişken otomatik depolama süresi vardır durumda ve bunun adresinin alınması yoktur, kod daima tanımsız davranış [1] çağırır.
  • Aksi takdirde, sistemin verilen değişken türü için tuzak temsillerini desteklemesi durumunda, kod her zaman tanımsız davranışı [2] çağırır.
  • Aksi takdirde, tuzak temsili yoksa, değişken belirtilmemiş bir değer alır. Değişken her okunduğunda bu belirtilmemiş değerin tutarlı olacağına dair bir garanti yoktur. Bununla birlikte, bir tuzak temsili olmayacağı garanti edilir ve bu nedenle tanımsız davranışı çağırmaması garanti edilir [3].

    Değer, daha sonra bir program çökmesine neden olmadan güvenli bir şekilde kullanılabilir, ancak bu tür kod, tuzak temsillerine sahip sistemler için taşınabilir değildir.


[1]: C11 6.3.2.1:

Lvalue, kayıt saklama sınıfıyla bildirilebilecek otomatik depolama süresi olan bir nesneyi belirtirse (adresi asla alınmamışsa) ve bu nesne başlatılmamışsa (bir başlatıcı ile bildirilmez ve kullanımdan önce ona atama yapılmamışsa) ), davranış tanımsızdır.

[2]: C11 6.2.6.1:

Belirli nesne temsillerinin, nesne türünün bir değerini temsil etmesi gerekmez. Bir nesnenin depolanan değeri böyle bir temsile sahipse ve karakter türü olmayan bir lvalue ifadesi tarafından okunursa, davranış tanımsızdır. Böyle bir temsil, karakter tipine sahip olmayan bir lvalue ifadesi tarafından nesnenin tamamını veya herhangi bir bölümünü değiştiren bir yan etki tarafından üretilirse, davranış tanımsızdır. 50) Böyle bir temsil, tuzak gösterimi olarak adlandırılır.

[3] C11:

3.19.2
Belirsiz değer
ya belirtilmemiş bir değer ya da tuzak temsili

3.19.3
belirtilmemiş değer
, bu Uluslararası Standardın herhangi bir durumda seçildiği değerin herhangi bir şartı getirmediği ilgili türün geçerli değeri
NOT Belirtilmemiş bir değer, bir tuzak temsili olamaz.

3.19.4
tuzak gösterimi
, nesne türünün bir değerini temsil etmesi gerekmeyen bir nesne temsili


3
@Vality Gerçek dünyada, tüm bilgisayarların% 99,9999'u tuzak gösterimleri olmayan ikinin tamamlayıcı CPU'larıdır. Bu nedenle hiçbir tuzak temsili norm değildir ve bu tür gerçek dünya bilgisayarlarındaki davranışı tartışmak oldukça önemlidir. Çılgınca egzotik bilgisayarların bir norm olduğunu varsaymak yardımcı olmaz. Gerçek dünyadaki tuzak temsilleri o kadar nadirdir ki standartta tuzak gösterimi teriminin varlığı, çoğunlukla 1980'lerden miras kalan standart bir kusur olarak görülmelidir. Tamamlayıcı ve işaret ve büyüklük bilgisayarları için destek olduğu gibi.
Lundin

3
Bu arada, bu, neden stdint.hher zaman yerel C türleri yerine kullanılması gerektiğinin mükemmel bir nedenidir . Çünkü stdint.h2'nin tamamlamasını zorlar ve dolgu bitleri yoktur. Başka bir deyişle, stdint.htürlerin saçmalıklarla dolu olmasına izin verilmez.
Lundin

2
Yine komitenin kusur raporuna cevabı şöyle diyor: "2. sorunun cevabı, belirsiz değerler üzerinde yapılan herhangi bir işlemin sonuç olarak belirsiz bir değere sahip olacağıdır." ve "3. sorunun cevabı, kütüphane fonksiyonlarının belirsiz değerler üzerinde kullanıldığında tanımsız davranışlar göstereceğidir."
Antti Haapala

2
DRs 451 ve 260
Antti Haapala

1
@AnttiHaapala Evet, DR'yi biliyorum. Bu cevapla çelişmiyor. Başlatılmamış bir bellek konumunu okurken belirsiz bir değer elde edebilirsiniz ve her seferinde aynı değer olması gerekmez. Ancak bu tanımlanmamış bir davranış, tanımlanmamış davranış değil .
Lundin

2

Pek çok yanıt, başlatılmamış kayıt erişimini tuzağa düşüren işlemcilere odaklanırken, UB'den yararlanmak için özel bir çaba göstermeyen derleyiciler kullanılarak bu tür tuzakları olmayan platformlarda bile ilginç davranışlar ortaya çıkabilir. Kodu düşünün:

Yükler ve depolar dışındaki tüm talimatların 32 bitlik kayıtlarda çalıştığı ARM gibi bir platform için bir derleyici, kodu aşağıdakine eşdeğer bir şekilde makul bir şekilde işleyebilir:

Uçucu okumalardan herhangi biri sıfır olmayan bir değer verirse, r0, 0 ... 65535 aralığında bir değerle yüklenecektir. Aksi takdirde, fonksiyon çağrıldığında tuttuğu değeri verir (yani x'e geçirilen değer), bu değer 0..65535 aralığında bir değer olmayabilir. Standart, türü uint16_t olan ancak değeri 0..65535 aralığı dışında olan değerin davranışını açıklamak için herhangi bir terminolojiye sahip değildir, ancak bu tür bir davranışı üretebilecek herhangi bir eylemin UB'yi çağırdığını söylemek dışında.


İlginç. Yani kabul edilen cevabın yanlış olduğunu mu söylüyorsun? Yoksa teoride doğru olduğunu söylüyorsunuz ama pratikte derleyiciler daha garip şeyler yapabilir mi?
user541686

@Mehrdad: Uygulamaların UB yokluğunda mümkün olabilecek sınırların ötesine geçen davranışlara sahip olması yaygındır. Sanırım Standart, "tahsis edilmiş" bitleri en kötü ihtimalle belirsiz bir şekilde davranacak, ancak belirleyici olmayan bir şekilde davranan ek üst bitlerle (örneğin, Yukarıdaki işlevin sonucu bir tür değişkeninde saklanır uint16_t, bu değişken bazen 123 ve bazen 6553623 olarak okunabilir). Sonuç göz ardı
edilirse

... veya herhangi bir olası yolla okunabileceği şekilde kullanıldığında, tüm gereklilikleri karşılayan nihai sonuçlar elde edilir, kısmen belirsiz değerin varlığı sorun olmamalıdır. Öte yandan, Standardın herhangi bir davranışsal gereklilik getireceği herhangi bir durumda, kısmen belirsiz değerlerin varlığına izin verecek hiçbir şey Standartta yoktur.
supercat

Değişken eğer - O da sizin tarif edilmektedir kabul cevap tam olarak ne olduğunu bana öyle geliyor olabilir ile ilan edilmiştir register, o zaman potansiyel olarak tanımlanmamış davranışı yapmak ekstra bit olabilir. Tam olarak bunu söylüyorsun, değil mi?
user541686

@Mehrdad: Kabul edilen yanıt, yazmaçları fazladan "başlatılmamış" duruma sahip mimarilere odaklanır ve başlatılmamış bir kayıt yüklenirse tuzaklanır. Bu tür mimariler vardır, ancak sıradan değildir. Sıradan bir donanımın, C Standardı tarafından tasarlanan herhangi bir şeyin dışında kalan, ancak bir derleyicinin karışıma kendi ek çılgınlığını eklememesi durumunda yararlı bir şekilde kısıtlanabilecek bir davranış sergileyebileceği bir senaryoyu anlatıyorum . Örneğin, bir işlevin gerçekleştirilecek bir işlemi seçen bir parametresi varsa ve bazı işlemler yararlı veriler döndürürken diğerleri döndürmez, ...
supercat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.