11 Mart 2019 Pazartesi

Signed/Unsigned Integer Karışımı

Giriş
Aslında kural olarak unsigned tipleri kullanmamak daha iyi. Çünkü çok fazla hataya sebep oluyor.

ALU
İşlemcinin içindeki ALU açısından signed veya unsigned için farklı instruction' lar bulunmuyor. İşlemin sonucunu yorumlamak tamamen programı yazan kişiye bağlı.

1. size() metodu Hataları
std::size_t container'ların size() metodu ile gelen bir unsigned tip ve hatalara sebep oluyor. Açıklaması şöyle. Yani container.size() metodunun herhangi bir tarafını signed sayı yapmak tehlikeli
Because of historical accident, the C++ standard also uses unsigned integers to represent the size of containers - many members of the standards body believe this to be a mistake, but it is effectively impossible to fix at this point. The fact that unsigned arithmetic doesn't model the behavior of a simple integer, but is instead defined by the standard to model modular arithmetic (wrapping around on overflow/underflow), means that a significant class of bugs cannot be diagnosed by the compiler.
2. Genel Kural
unsigned some operator signed işleminde sonuç unsigned çıkar.

Genel Kural Dair Örnekler

Eksi Signed < unsigned Yapmak Hatalıdır
Elimizde şöyle bir kod olsun. Burada beklenti vector'ün -1. elemanına erişmeye çalışınca exception fırlatılması ancak -1 unsigned tipe dönüştürülünce aslında döngüye hiç girmiyor.
std::vector<double> vd{ 1.5 };

try {
  for (int i = -1; i < vd.size(); ++i) 
    double d = vd.at(i); // exception is not thrown. Why?

} catch (std::out_of_range& re) {
  std::cout << "Exception is " << re.what() << std::endl; // exception is not thrown
}

unsigned değer 0 ise -1 yapmak hatalıdır. 
Örnek
Boş vector'de şu kod yanlış çalışır
for (size_t i = 0; i < v.size() - 1; i++) { // do something }
Şöyle yapmak gerekir.
for (size_t i = 0; i + 1 < v.size(); i++) { // do something }
Örnek
Şöyle yapmak gerekir.
for (int i = 0; i < v.size() - 5; ++i) { foo(v[i]); } // Incorrect
// for (int i = 0; i + 5 < v.size(); ++i) { foo(v[i]); } // Correct
Ternary Operator
Açıklaması şöyle.
The type of a ? b : c is not dependent on a. It is determined unconditionally by the types of b and c. ...For int and unsigned int, the resulting type is unsigned int.
Örnek
Elimizde şöyle bir kod olsun. unsigned > signed işleminde signed taraf unsigned'a çevrilir. signed -1 çok büyük bir unsigned değer olacağı için sonuç 0 çıkar.
signed int test = -1;
signed int si = 1;
unsigned int ui = 2;

printf("%d\n", ((1 ? si : ui) > test));
return 0;

(Unsgined - Int) İşleminde Sonuç Unsigned Olur
Örnek
Elimizde şöyle bir kod olsun.
unsigned int t = 10;
int d = 16;
float c = t - d; //4294967290u
int e = t - d; //-6
Sonuç unsigned olduğu için c artı değer alırken e eksi değer alıyor.

(Unsgined + Int) İşleminde Sonuç Unsigned Olur
Örnek
Açıklaması şöyle.
In the second expression, the int value -42 is converted to unsigned before the addition is done. Converting a negative number to unsigned behaves exactly as if we had attempted to assign that negative value to an unsigned object. The value “wraps around” as described above.
Şöyle yaparız.
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
(- Unsigned) İşleminde Sonuç Unsigned Olur
Örnek
Elimizde şöyle bir kod olsun.
#include <iostream>

int main() {
  unsigned int a = 10;
  int b = -a;
  std::cout << b << ", " << -a << std::endl;
}
Açıklaması şöyle.
-a is evaluated in unsigned arithmetic, and will be a number larger than std::numeric_limits<int>::max(). The unary operator - when applied to an unsigned type acts more like a modulus operator.

Hiç yorum yok:

Yorum Gönder