Bayrak numaralandırmaları neden genellikle onaltılık değerlerle tanımlanır?


122

Çoğu zaman onaltılık değerler kullanan bayrak enum bildirimleri görüyorum. Örneğin:

[Flags]
public enum MyEnum
{
    None  = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4,
    Flag4 = 0x8,
    Flag5 = 0x10
}

Bir sıralama beyan ettiğimde, genellikle şu şekilde beyan ederim:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16
}

Bazı insanların değeri ondalık yerine onaltılık olarak yazmayı seçmesinin bir nedeni veya mantığı var mı? Gördüğüm kadarıyla, onaltılık değerleri kullanırken kafanızın karışması ve Flag5 = 0x16bunun yerine yanlışlıkla yazmak daha kolay Flag5 = 0x10.


4
Daha az olasılıkla yazacağım bir şey yapmış Ne 10ziyade 0x10sen ondalık sayılar kullanılırsa? Özellikle bunlar uğraştığımız ikili sayılar olduğundan ve onaltılık önemsiz bir şekilde ikiliye / ikiliden dönüştürülebilir mi? 0x111birinin kafasından tercüme etmek 273...
cHao

4
C # 'ın ikinin güçlerini yazmayı açıkça gerektirmeyen bir sözdizimine sahip olmaması utanç verici.
Albay Panic

Burada saçma sapan bir şey yapıyorsun. Bayrakların ardındaki amaç, bitsel olarak birleştirilmeleridir. Ancak bitsel kombinasyonlar, türün öğeleri değildir. Değer Flag1 | Flag23'tür ve 3 herhangi bir alan değerine karşılık gelmez MyEnum.
Kaz

Onu nerede göruyorsun? reflektörlü?
giammin

@giammin Bu genel bir sorudur, belirli bir uygulama hakkında değil. Örneğin, açık kaynaklı projeleri veya sadece internette bulunan kodu alabilirsiniz.
Adi Lester

Yanıtlar:


184

Gerekçeler farklı olabilir, ancak gördüğüm bir avantaj, onaltılı tabanın size şunu hatırlatmasıdır: "Tamam, artık rastgele insan icat edilmiş on üssünde sayılarla uğraşmıyoruz. Bitlerle uğraşıyoruz - makinenin dünyası - ve biz kurallarına göre oynayacağız. " Onaltılık, verilerin bellek düzeninin önemli olduğu nispeten düşük seviyeli konularla uğraşmadığınız sürece nadiren kullanılır. Bunu kullanmak, şu anda içinde bulunduğumuz durumun bu olduğu gerçeğine işaret ediyor.

Ayrıca, C # konusunda emin değilim, ancak C'nin x << ygeçerli bir derleme zamanı sabiti olduğunu biliyorum . Bit kaydırma kullanmak en net olanıdır:

[Flags]
public enum MyEnum
{
    None  = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4
}

7
Bu çok ilginç ve aslında geçerli bir C # numaralandırması.
Adi Lester

13
Bu gösterimle +1, sıralama değeri hesaplamalarında asla hata yapmazsınız
Sergey Berezovskiy

1
@AllonGuralnek: Derleyici [Flags] ek açıklamasına göre benzersiz bit konumları atıyor mu? Genellikle 0'dan başlar ve 1'lik artışlarla gider, bu nedenle 3 (ondalık) atanan herhangi bir enum değeri ikili olarak 11 olur ve iki biti ayarlar.
Eric J.

2
@Eric: Huh, neden bilmiyorum ama ikisinin güç değerlerini atadığından her zaman emindim. Az önce kontrol ettim ve sanırım yanılmışım.
Allon Guralnek

38
x << yGösterimle bir başka eğlenceli gerçek . 1 << 10 = KB, 1 << 20 = MB, 1 << 30 = GBVe bu kadar. Gidebileceğiniz bir arabellek için 16 KB'lik bir dizi yapmak istiyorsanız gerçekten çok güzelvar buffer = new byte[16 << 10];
Scott Chamberlain

43

Bunların ikili bayraklar olduğunu görmeyi kolaylaştırır .

None  = 0x0,  // == 00000
Flag1 = 0x1,  // == 00001
Flag2 = 0x2,  // == 00010
Flag3 = 0x4,  // == 00100
Flag4 = 0x8,  // == 01000
Flag5 = 0x10  // == 10000

Gerçi ilerleme bile net yapar:

Flag6 = 0x20  // == 00100000
Flag7 = 0x40  // == 01000000
Flag8 = 0x80  // == 10000000

3
Aslında 0x1, 0x2, 0x4, 0x8'in önüne 0 ekliyorum ... Bu yüzden 0x01, 0x02, 0x04, 0x08 ve 0x10 alıyorum ... Bunu okumayı daha kolay buluyorum. Bir şeyi mahvediyor muyum?
LightStriker

4
@Light - Hiç de değil. Çok yaygındır, bu yüzden bunların nasıl hizalandığını görebilirsiniz. Sadece bitleri daha belirgin hale getirir :)
Oded

2
@LightStriker , hex kullanmıyorsanız , onu oraya atacak . Yalnızca sıfır ile başlayan değerler sekizlik olarak yorumlanır. Yani 012aslında 10.
Jonathon Reinhart

@JonathonRainhart: Biliyorum. Ama bitfields kullanırken her zaman hex kullanırım. Bunun intyerine kendimi güvende hissedeceğimi sanmıyorum . Aptalca olduğunu biliyorum ... ama alışkanlıklar zor ölür.
LightStriker

36

Ben dizisi hep 1,2,4,8 ve daha sonra bir 0'a eklemek sırf bu olduğunu düşünüyorum
Gördüğünüz gibi:

0x1 = 1 
0x2 = 2
0x4 = 4
0x8 = 8
0x10 = 16
0x20 = 32
0x40 = 64
0x80 = 128
0x100 = 256
0x200 = 512
0x400 = 1024
0x800 = 2048

1-2-4-8 dizisini hatırladığınız sürece, 2'nin güçlerini hatırlamak zorunda kalmadan sonraki tüm bayrakları oluşturabilirsiniz.


13

Çünkü [Flags]numaralamanın gerçekten bir bit alanı olduğu anlamına gelir . İle bayrakları birleştirmek için [Flags]bitsel AND ( &) ve OR ( |) operatörlerini kullanabilirsiniz. Bunun gibi ikili değerlerle uğraşırken, onaltılık değerlerin kullanılması neredeyse her zaman daha açıktır. İlk etapta onaltılı kullanmamızın nedeni budur . Her bir onaltılık karakter tam olarak bir yarım bayta (dört bit) karşılık gelir . Ondalık ile bu 1'den 4'e eşleme doğru değildir.


2
Bitsel işlemleri kullanma yeteneğinin, bayrak niteliği ile hiçbir ilgisi yoktur.
Mattias Nordqvist

4

Çünkü hex'de ikinin gücünü ikiye katlamanın mekanik ve basit bir yolu var. Ondalık olarak bu zordur. Kafanızda uzun bir çarpma gerektirir. Onaltılık olarak basit bir değişikliktir. Bunu 1UL << 63ondalık olarak yapamayacağınız kadar yapabilirsiniz.


1
Bunun en mantıklı olduğunu düşünüyorum. Büyük bir değer kümesine sahip numaralandırmalar için en kolay yoldur (@ Hypercube örneğinin olası istisnası dışında).
Adi Lester

3

Çünkü bitlerin bayrakta olduğu insanlar için takip etmek daha kolay. Her onaltılık rakam 4 bitlik bir ikiliye sığabilir.

0x0 = 0000
0x1 = 0001
0x2 = 0010
0x3 = 0011

... and so on

0xF = 1111

Tipik olarak bayraklarınızın bitlerle örtüşmemesini istersiniz, bunu yapmanın ve görselleştirmenin en kolay yolu, bayraklarınızı bildirmek için onaltılık değerler kullanmaktır.

Dolayısıyla, 16 bitlik bayraklara ihtiyacınız varsa, 4 basamaklı onaltılık değerler kullanacaksınız ve bu şekilde hatalı değerlerden kaçınabilirsiniz:

0x0001 //= 1 = 000000000000 0001
0x0002 //= 2 = 000000000000 0010
0x0004 //= 4 = 000000000000 0100
0x0008 //= 8 = 000000000000 1000
...
0x0010 //= 16 = 0000 0000 0001 0000
0x0020 //= 32 = 0000 0000 0010 0000
...
0x8000 //= 32768 = 1000 0000 0000 0000

Bu açıklama iyidir .... Eksik olan tek şey bitlerin,
atlamaların
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.