bağlam
Başlangıçta PIC mikrodenetleyici için 8 bit C derleyicisi kullanılarak derlenen C kodunu taşıyoruz. İmzasız global değişkenlerin (örneğin, hata sayaçları) sıfıra geri dönmesini önlemek için kullanılan yaygın bir deyim şudur:
if(~counter) counter++;
Bitsel operatör burada tüm bitleri tersine çevirir ve ifade sadece counter
maksimum değerden azsa doğrudur . Daha da önemlisi, bu değişken büyüklüğünden bağımsız olarak çalışır.
Sorun
Şimdi GCC kullanarak 32 bit ARM işlemcisini hedefliyoruz. Aynı kodun farklı sonuçlar verdiğini fark ettik. Anlayabildiğimiz kadarıyla, bitsel tamamlayıcı işleminin beklediğimizden farklı bir değer döndürdüğü anlaşılıyor. Bunu çoğaltmak için GCC'de derliyoruz:
uint8_t i = 0;
int sz;
sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1
sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4
İlk çıktı satırında, beklediğimiz şeyi elde ederiz: i
1 byte. Bununla birlikte, bitsel tamamlayıcısı i
aslında dört bayttır, bu da soruna neden olur, çünkü şimdi bununla karşılaştırmalar beklenen sonuçları vermeyecektir. Örneğin, ( i
uygun şekilde başlatılmışsa uint8_t
) yapıyorsa :
if(~i) i++;
i
0xFF'den 0x00'e kadar "sarın" göreceğiz . Bu davranış GCC'de önceki derleyicide ve 8 bit PIC mikro denetleyicide amaçladığımız gibi çalıştığından farklıdır.
Bunu şu şekilde döküm yaparak çözebileceğimizin farkındayız:
if((uint8_t)~i) i++;
Veya tarafından
if(i < 0xFF) i++;
Ancak bu geçici çözümlerin her ikisinde de değişkenin boyutu bilinmelidir ve yazılım geliştiricisi için hataya açıktır. Bu tür üst sınır kontrolleri kod tabanı boyunca gerçekleşir. Orada değişkenlerin çoklu boyutları (örn., uint16_t
Ve unsigned char
vb) ve bir başka çalışma kod temeli bu değişen biz gözle bekliyoruz şey değildir.
Soru
Sorunu anlamamız doğru mu ve bunu çözmek için bu deyimi kullandığımız her vakayı tekrar ziyaret etmenizi gerektirmeyen seçenekler var mı? Bitsel tamamlayıcı gibi bir işlemin işlenenle aynı boyutta bir sonuç döndürmesi gerektiği varsayımımız doğru mu? İşlemci mimarilerine bağlı olarak bunun kırılacağı anlaşılıyor. Çılgın haplar alıyorum ve C'nin bundan biraz daha taşınabilir olması gerektiğini hissediyorum. Yine, bu anlayışımız yanlış olabilir.
Yüzeyde bu büyük bir sorun gibi görünmeyebilir, ancak daha önce çalışan bu deyim yüzlerce yerde kullanılıyor ve pahalı değişikliklere devam etmeden önce bunu anlamaya istekliyiz.
Not: Görünüşte benzer ancak tam olarak yinelenmeyen bir soru var: Char'da bitsel işlem 32 bit sonuç veriyor
Burada tartışılan konunun asıl sorununu görmedim, yani bitsel bir tamamlayıcının sonuç büyüklüğü operatöre geçirilenden farklıydı.