Giriş
Açıklaması şöyle.
Bu tür hataları yakalamak için derleyicinin tipine bağlı olarak şuna benzer birşey yaparız.
Pointer'ı array'e çeviremeyiz.
Örnek
Bu kod yanlış.
Herhangi bir nesneye char pointer olarak erişebilirim.Eğer char tipindeki bellek alanını daha büyük bir tipin pointer'ına çevirip kullanırsam hata olur.
Genel Çözüm
Genel çözüm daha büyük tipe kopyalamak şeklinde. Şöyle yaparız.
Elimizde şöyle bir kod olsun.
Şöyle yapamayız. char tipindeki bellek alanına erişmek için float pointer kullanılıyor.
Şöyle yapamayız. Şu kod char tipindeki bellek alanına erişmek için short pointer kullanıyor.
Elimizde değişken ve değişkenin bellek alanına erişen pointer'lar olsun.
float'tan int'e dönüşüm
Şöyle yapamayız. float 2 ile bölündükten sonra int gibi kullanılmaya çalışılıyor.
Açıklaması şöyle.
strict aliasing is about accessing an object via a glvalue of the wrong type.Açıklaması şöyle.
Strict aliasing belli bir tipteki bellek alanının başka bir tipe çevrilerek kullanılmasının yasak olması anlamına gelir.If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
the dynamic type of the object, a cv-qualified version of the dynamic type of the object,- a type similar (as defined in 4.4) to the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
- an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
- a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
- a char or unsigned char type.
Bu tür hataları yakalamak için derleyicinin tipine bağlı olarak şuna benzer birşey yaparız.
enable -fstrict-aliasing -Wstrict-aliasing=2
Pointer'ı Array' DönüşümPointer'ı array'e çeviremeyiz.
Örnek
Bu kod yanlış.
std::array<int, 8> a;
auto p = reinterpret_cast<int(*)[8]>(a.data());
(*p)[0] = 42;
Char Tipinden Daha Byük Bir Tipe Cast Ederek ErişimHerhangi bir nesneye char pointer olarak erişebilirim.Eğer char tipindeki bellek alanını daha büyük bir tipin pointer'ına çevirip kullanırsam hata olur.
Genel Çözüm
Genel çözüm daha büyük tipe kopyalamak şeklinde. Şöyle yaparız.
uint16_t getMessageAt(const Message& msg, size_t i) {
uint16_t tmp;
memcpy(&tmp, msg.payload.data() + 2 * i, 2);
return tmp;
}
ÖrnekElimizde şöyle bir kod olsun.
struct Message {
int msg_type;
std::vector<uint8_t> payload;
};
Şöyle yapamayız. uint8_t tipindeki bellek alanına erişmek için uint16_t pointer kullanılıyor.const uint16_t* a = reinterpret_cast<uint16_t*>(msg.payload.data());
ÖrnekŞöyle yapamayız. char tipindeki bellek alanına erişmek için float pointer kullanılıyor.
void a() {
std::vector<char> v(sizeof(float));
float *f = reinterpret_cast<float *>(v.data());
*f = 42;
}
void b() {
char *a = new char[sizeof(float)];
float *f = reinterpret_cast<float *>(a);
*f = 42;
}
ÖrnekŞöyle yapamayız. Şu kod char tipindeki bellek alanına erişmek için short pointer kullanıyor.
short A[] = {1, 2, 3, 4, 5, 6};
std::cout << *(short*)((char*)A + 7) << std::endl;
Şöyle yaparızshort A[] = {1, 2, 3, 4, 5, 6};
short B;
std::copy(
(char*)A + 7,
(char*)A + 7 + sizeof(short),
(char*)&B
);
std::cout << std::showbase << std::hex << B << std::endl;
ÖrnekElimizde değişken ve değişkenin bellek alanına erişen pointer'lar olsun.
constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e;
// a.k.a. Clockwise-Rotated Endian which allocates like
// char[8] = { n,a,i,d,n,e,\0,\0 }
const auto& arr = // std::array<char,8> &
reinterpret_cast<const std::array<char,8> &> (lil_endian); //1
const auto& carr = // char(&)[8]>
reinterpret_cast<const char(&)[8]> (lil_endian); //2
const auto* p = // char *
reinterpret_cast<const char *>(std::addressof(lil_endian)); //3
Bu pointer'ları kullanarak std::string nesneleri yaratalım.const auto str1 = std::string(arr.crbegin()+2, arr.crend() );
const auto str2 = std::string(std::crbegin(carr)+2, std::crend(carr) );
const auto sv3r = std::string_view(p, 8);
const auto str3 = std::string(sv3r.crbegin()+2, sv3r.crend() );
1 ve 2 Undefined Behavior'a sebep olur. Çünkü nesnenin bellek alanına char veya unsigned char olarak erişmedim.float'tan int'e dönüşüm
Şöyle yapamayız. float 2 ile bölündükten sonra int gibi kullanılmaya çalışılıyor.
float sqrt(float f)
{
const int result = 0x1fbb4000 + (*(int*)&f >> 1);
return *(float*)&result;
}
Hiç yorum yok:
Yorum Gönder