union
Son gruptan başka bir üyeye erişmenin UB olduğu izlenimine kapıldım, ancak sağlam bir referans bulamıyorum (UB olduğunu iddia eden ancak standarttan herhangi bir destek olmadan cevaplar dışında).
Öyleyse, tanımlanmamış bir davranış mı?
union
Son gruptan başka bir üyeye erişmenin UB olduğu izlenimine kapıldım, ancak sağlam bir referans bulamıyorum (UB olduğunu iddia eden ancak standarttan herhangi bir destek olmadan cevaplar dışında).
Öyleyse, tanımlanmamış bir davranış mı?
Yanıtlar:
Buradaki karışıklık, C'nin bir birleşim yoluyla tür-punning'e açıkça izin vermesidir, oysa C ++ (c ++ 11) böyle bir izne sahip değildir.
6.5.2.3 Yapı ve sendika üyeleri
95) Bir birleşim nesnesinin içeriğini okumak için kullanılan üye, nesnede bir değer depolamak için en son kullanılan üye ile aynı değilse, değerin nesne temsilinin uygun kısmı, yeni nesnede bir nesne temsili olarak yeniden yorumlanır. 6.2.6'da açıklandığı gibi yazın (bazen '' tip punning '' olarak adlandırılan bir işlem). Bu bir tuzak temsili olabilir.
C ++ ile durum:
9.5 Sendikalar [class.union]
Bir birleşimde, statik olmayan veri üyelerinden en fazla biri herhangi bir zamanda aktif olabilir, yani statik olmayan veri üyelerinden en fazla birinin değeri herhangi bir zamanda bir birleşimde depolanabilir.
C ++ daha sonra struct
ortak başlangıç dizilerine sahip s içeren birliklerin kullanımına izin veren bir dile sahiptir ; ancak bu tür karıştırmaya izin vermez.
Sendika tip-cinaslı olmadığını belirlemek için olan C izin ++, daha fazla aramak zorunda. Hatırlamakc99 C ++ 11 için normatif bir referanstır (ve C99, birleşim tipi çalıştırmaya izin veren C11'e benzer dile sahiptir):
3.9 Türler [basic.types]
4 - T tipi bir nesnenin nesne temsili, N'nin sizeof (T) 'ye eşit olduğu, T tipi nesne tarafından alınan N işaretsiz karakter nesnesi dizisidir. Bir nesnenin değer temsili, T tipi değerini tutan bit kümesidir. Önemsiz şekilde kopyalanabilir türler için, değer temsili, bir uygulamanın ayrı bir öğesi olan bir değeri belirleyen nesne gösteriminde bir bit kümesidir. tanımlanmış değerler kümesi. 42
42) Amaç, C ++ bellek modelinin ISO / IEC 9899 Programlama Dili C ile uyumlu olmasıdır.
Okurken özellikle ilginçleşiyor
3.8 Nesne ömrü [basic.life]
T tipi bir nesnenin ömrü şu durumlarda başlar: - T tipi için uygun hizalama ve boyuta sahip depolama elde edildiğinde ve - nesne önemsiz olmayan bir başlatmaya sahipse, başlatması tamamlanır.
Dolayısıyla , bir birleşimde bulunan ( ipso facto'nun önemsiz başlatmaya sahip olduğu) ilkel bir tür için , nesnenin ömrü, en azından birleşmenin kendi yaşam süresini kapsar. Bu bizi çağırmamızı sağlar
3.9.2 Bileşik türleri [temel bileşik]
Bir A adresinde T tipi bir nesne bulunuyorsa, değeri A adresi olan cv T * türünde bir göstericinin, değerin nasıl elde edildiğine bakılmaksızın bu nesneyi işaret ettiği söylenir.
İlgilendiğimiz işlemin tip-punning olduğunu varsayarsak, yani aktif olmayan bir sendika üyesinin değerini almak ve yukarıda belirtilen üye tarafından atıfta bulunulan nesneye geçerli bir referansımız olduğu için, bu işlem lvalue-to -rvalue dönüşümü:
4.1 Ldeğer-değer dönüşümü [dönş.lval]
İşlevsiz, dizi olmayan türden
T
bir glvalue, prvalue'ya dönüştürülebilir. EğerT
eksik bir tip, kötü oluşturulan bu dönüşümü gerektiren bir programdır. Glvalue'nun başvurduğuT
nesne bir türT
nesnesi değilse ve türetilen türde bir nesne değilse veya nesne başlatılmamışsa, bu dönüştürmeyi gerektiren bir programın tanımlanmamış bir davranışı vardır.
O zaman soru, aktif olmayan bir birlik üyesi olan bir nesnenin, aktif birlik üyesine depolama tarafından başlatılıp başlatılmadığıdır. Söyleyebileceğim kadarıyla durum böyle değil ve bu nedenle eğer:
char
dizi depolamaya kopyalanır ve geri alınır (3.9: 2) veyaaktif olmayan bir üye tarafından bir birliğe erişim tanımlanır ve nesne ve değer temsilini takip edecek şekilde tanımlanır, yukarıdaki ara konumlardan biri olmadan erişim tanımsız bir davranıştır. Uygulama, elbette tanımsız davranışın meydana gelmediğini varsayabileceğinden, bunun, böyle bir programda gerçekleştirilmesine izin verilen optimizasyonlara etkileri vardır.
Yani, aktif olmayan bir sendika üyesine meşru olarak bir değer oluşturabilsek de (bu nedenle, inşaat olmadan aktif olmayan bir üyeye atama yapmak uygundur) başlatılmamış olarak kabul edilir.
memcpy
uygulamalara izin vermedi (nesnelere unsigned char
ldeğerleri kullanarak erişme ), *p
sonrasına erişime izin vermedi int *p = 0; const int *const *pp = &p;
('den' int**
e örtük dönüştürme const int*const*
geçerli olsa bile), c
sonrasına erişime bile izin vermedi struct S s; const S &c = s;
. CWG sorunu 616 . Yeni ifade izin veriyor mu? Ayrıca [basic.lval] var.
&
Bir sendika üyesine uygulandığında tekli operatörün ne anlama geldiğini açıklığa kavuşturması gerekse de (ve C Standardının ayrıca açıklığa kavuşturması gerekir) bu mantıklı olacaktır . Ortaya çıkan göstericinin en azından bir sonraki sefere başka bir üye lvalue'nun bir sonraki doğrudan veya dolaylı kullanımına kadar üyeye erişmek için kullanılabilir olması gerektiğini düşünüyorum, ancak gcc'de işaretçi o kadar uzun süre bile kullanılamıyor, bu da bir soruyu gündeme getiriyor. &
operatör ortalama gerekiyordu.
C ++ 11 standardı bu şekilde söylüyor
9.5 Birlikler
Bir birleşimde, statik olmayan veri üyelerinden en fazla biri herhangi bir zamanda aktif olabilir, yani statik olmayan veri üyelerinden en fazla birinin değeri herhangi bir zamanda bir birleşimde depolanabilir.
Yalnızca bir değer saklanıyorsa, diğerini nasıl okuyabilirsiniz? Sadece orada değil.
Gcc belgeleri bunu Uygulama tanımlı davranış altında listeler
- Bir birleşim nesnesinin üyesine, farklı türden bir üye kullanılarak erişilir (C90 6.3.2.3).
Nesnenin temsilinin ilgili baytları, erişim için kullanılan türde bir nesne olarak değerlendirilir. Bkz. Yazma işlemi. Bu bir tuzak temsili olabilir.
bunun C standardı için gerekli olmadığını gösterir.
2016-01-05: Yorumlar aracılığıyla , C standart belgesine dipnot olarak benzer bir metin ekleyen C99 Kusur Raporu # 283'e bağlandım :
78a) Bir birleşim nesnesinin içeriğine erişmek için kullanılan üye, nesnede bir değer depolamak için en son kullanılan üye ile aynı değilse, değerin nesne temsilinin uygun kısmı, yeni nesnede bir nesne temsili olarak yeniden yorumlanır. 6.2.6'da açıklandığı gibi yazın (bazen "tür punning" olarak adlandırılan bir işlem). Bu bir tuzak temsili olabilir.
Bir dipnotun standart için normatif olmadığını düşünürsek, pek açıklığa kavuşturup açmadığından emin değilim.
Sanırım standardın tanımlanmamış davranış olduğunu söylemeye en yakın olanı, ortak bir başlangıç dizisi içeren bir birleşim için davranışı tanımladığı yerdir (C99, §6.5.2.3 / 5):
Sendikaların kullanımını basitleştirmek için özel bir garanti verilir: Bir birlik ortak bir başlangıç sırasını paylaşan birkaç yapı içeriyorsa (aşağıya bakınız) ve birleşim nesnesi şu anda bu yapılardan birini içeriyorsa, ortak olanı incelemeye izin verilir. sendikanın tam türünün bir beyanının görülebildiği herhangi bir yerin ilk kısmı. Karşılık gelen üyelerin bir veya daha fazla ilk üye dizisi için uyumlu tipleri (ve bit alanları için aynı genişlikleri) varsa, iki yapı ortak bir başlangıç dizisini paylaşır.
C ++ 11, §9.2 / 19'da benzer gereksinimleri / izni verir:
Bir standart düzen birleşimi, ortak bir ilk sırayı paylaşan iki veya daha fazla standart düzen yapısı içeriyorsa ve standart düzen birleşim nesnesi şu anda bu standart yerleşim yapılarından birini içeriyorsa, herhangi bir ortak başlangıç bölümünü incelemesine izin verilir. onların. Karşılık gelen üyelerin mizanpajla uyumlu türleri varsa ve hiçbir üye bir bit alanı değilse veya her ikisi de bir veya daha fazla ilk üye dizisi için aynı genişliğe sahip bit alanları ise, iki standart-yerleşim yapısı ortak bir başlangıç sırasını paylaşır.
Her ikisi de doğrudan ifade etmese de, her ikisi de bir üyeyi "incelemeye" (okumaya) yalnızca "izin verildiğine" dair güçlü bir ima taşır. 1) üye en son (bir parçası) yazıyorsa veya 2) ortak bir baş harfin parçasıysa sıra.
Bu, başka türlü yapmanın tanımlanmamış davranış olduğuna dair doğrudan bir ifade değil, ama benim en yakın bildiğim şey bu.
union
Belirli bir blog tarafından bunun iyi olduğu izlenimi verildiğinden ve etrafında birkaç büyük yapı ve proje inşa ettiğimden, tanımlanmamış s'nin en gizli kullanımlarını ilk okuduğumda çok öfkeliydim . Şimdi düşünüyorum benim beri, sonuçta Tamam olabilir union
ler ön aynı türde olan sınıfları ihtiva ettiğini ortaya çıkarmaktadır
union
içeren örneğin bir uint8_t
ve class Something { uint8_t myByte; [...] };
- Ben de burada geçerli olacak bu koşulu karşılamaktadır varsayılabilir, ama çok kasıtlı sadece izin vermek için ifadeli oluyor struct
s. Neyse ki ham ilkellerin yerine bunları zaten kullanıyorum: O
Mevcut cevaplarda henüz bahsedilmeyen bir şey, 6.2.5 bölümünün 21. paragrafındaki 37 no'lu dipnottur:
Birleştirme türüne sahip bir nesne aynı anda yalnızca bir üye içerebileceğinden, toplama türünün birleşim türünü içermediğini unutmayın.
Bu gereklilik açıkça bir üyeye yazıp başka birinde okumamanız gerektiğini ima ediyor gibi görünüyor. Bu durumda, spesifikasyon eksikliği nedeniyle tanımlanmamış bir davranış olabilir.
Bunu bir örnekle iyi açıklarım.
aşağıdaki birliğe sahip olduğumuzu varsayalım:
union A{
int x;
short y[2];
};
Bunun sizeof(int)
4 verdiğini ve bunun sizeof(short)
da 2
verdiğini varsayıyorum, union A a = {10}
bu kadar iyi yazarsanız , A tipi yeni bir varyasyon yaratın, içine 10 değerini koyun.
hafızanız şöyle görünmeli: (tüm sendika üyelerinin aynı yeri aldığını unutmayın)
| x | | y [0] | y [1] | ----------------------------------------- a-> | 0000 0000 | 0000 0000 | 0000 0000 | 0000 1010 | -----------------------------------------
görebileceğiniz gibi, ax'in değeri 10, ay 1'in değeri 10 ve ay [0] 'ın değeri 0'dır.
şimdi, bunu yaparsam ne olur?
a.y[0] = 37;
hafızamız şöyle görünecek:
| x | | y [0] | y [1] | ----------------------------------------- a-> | 0000 0000 | 0010 0101 | 0000 0000 | 0000 1010 | -----------------------------------------
bu ax değerini 2424842'ye (ondalık olarak) çevirecektir.
şimdi, sendikanızda bir kayan nokta varsa veya iki katına çıkarsa, tam sayıları kaydetme şekliniz nedeniyle hafıza haritanız daha karışık olabilir. buradan daha fazla bilgi edinebilirsiniz .