Bir struct
ile bir union
arasındaki farkı gösteren iyi bir örnek var mı?
Temel olarak biliyorum ki struct
üyesinin tüm hafızasını kullanır ve union
en büyük üyenin hafıza alanını kullanır. İşletim sistemi düzeyinde başka bir fark var mı?
Bir union ile, öğelerden yalnızca birini kullanmanız gerekir, çünkü hepsi aynı noktada saklanır. Bu, birkaç türden biri olabilecek bir şeyi saklamak istediğinizde kullanışlı olmasını sağlar. Öte yandan bir struct, öğelerinin her biri için ayrı bir bellek konumuna sahiptir ve hepsi aynı anda kullanılabilir.
Kullanımlarına somut bir örnek vermek gerekirse, bir süre önce bir Scheme yorumlayıcısı üzerinde çalışıyordum ve aslında Scheme veri tiplerini C veri tiplerinin üzerine bindiriyordum. Bu, bir struct içinde değerin türünü gösteren bir enum ve bu değeri saklamak için bir union depolamayı içeriyordu.
union foo {
int a; // can't use both a and b at once
char b;
} foo;
struct bar {
int a; // can use both a and b simultaneously
char b;
} bar;
union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!
struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK
düzenle: x.b'yi 'c' olarak ayarlamanın x.a'nın değerini neye değiştirdiğini merak ediyorsanız, teknik olarak bu tanımsızdır. Çoğu modern makinede bir char 1 bayt ve bir int 4 bayttır, bu nedenle x.b'ye 'c' değerini vermek aynı zamanda x.a'nın ilk baytına da aynı değeri verir:
union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);
Baskılar
99, 99
İki değer neden aynı? Çünkü int 3'ün son 3 baytının tümü sıfırdır, bu nedenle 99 olarak da okunur. x.a için daha büyük bir sayı girersek, durumun her zaman böyle olmadığını göreceksiniz:
union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);
Baskılar
387427, 99
Gerçek bellek değerlerine daha yakından bakmak için, değerleri hex olarak ayarlayalım ve yazdıralım:
union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);
Baskılar
deadbe22, 22
0x22'nin 0xEF'nin üzerine nerede yazdığını açıkça görebilirsiniz.
FAKAT
C'de, bir int içindeki baytların sırası tanımlanmamıştır. Bu program Mac'imde 0xEF'nin üzerine 0x22 yazdı, ancak int'i oluşturan baytların sırası tersine çevrildiği için 0xDE'nin üzerine yazacağı başka platformlar da var. Bu nedenle, bir program yazarken, bir union'daki belirli verilerin üzerine yazma davranışına asla güvenmemelisiniz çünkü bu taşınabilir değildir.
Baytların sıralanması hakkında daha fazla bilgi için endianness'e göz atın.