Endian etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Endian etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

28 Nisan 2021 Çarşamba

std::endian

Örnek
Şöyle yaparız
void convertBigToLittleEndianIfNecessary(uint32_t& code) {
  if constexpr (std::endian::native == std::endian::little) {
  code = ((code & 0xFF000000) >> 24) |
         ((code & 0x00FF0000) >> 8)  |
         ((code & 0x0000FF00) >> 8)  |
         ((code & 0x000000FF) >> 24);
    }
}

10 Temmuz 2018 Salı

Endian Agnostic

Giriş
Portable kod yazmak için Endian Agnostic yöntemleri kullanmak gerekir. Agnostic denmesinin sebebi kendi işlemcimin mimarisi ile ilgilenmemem. Sadece veriyi big endian mı yoksa little endian mı göndermek istememle ilgileniyorum.

Bu yöntemi kullanmazsak
1. Kodun içine #if BIG_ENDIAN ya da #if LITTLE_ENDIAN gibi macrolar koymak gerekir.
2. Daha sonra little endian ise htons(), htonl() çağrıları  yapmak gerekir.
Float tipler için bu çağrılar yoksa şöyle yaparız.
float f = 1.2f;
auto it = reinterpret_cast<uint8_t*>(&f);
std::reverse(it, it + sizeof(f)); //f is now in the reversed endianness

Big Endian Gönder ve Al
Socket kullanımından dolayı Big Endian okuma yazma işlemleri için hazır gelen htons, ntohs veya htonl, ntohl gibi metodlar kullanılır.

Eğer bu tür metodlar sistemimizde yoksa kendimiz de kolayca yazabiliriz. Altta yatan mantık çok basit.

Yazma
Şöyle yaparız. Buffer açısından bakarsak her zaman yazmaya LSB byte'tan başlarız. Yani Buffer'ın ilk alanından yazmaya başlarız. Bellegi soldan sağa okuduğumuzu düşünürsek bu aslında byte'ların ters çevrilmesi gibidir.
uint32_t i = ...;
uint8_t buf[4];
buf[0] = (i&0xff000000) >> 24;
buf[1] = (i&0x00ff0000) >> 16;
buf[2] = (i&0x0000ff00) >> 8;
buf[3] = (i&0x000000ff);
write(fd, buf, sizeof buf);
Okuma
Şöyle yaparız.
uint32_t i;
uint8_t buf[4];
read(fd, buf, sizeof buf);
i  = (uint32_t)buf[0] << 24;
i |= (uint32_t)buf[1] << 16;
i |= (uint32_t)buf[2] << 8;
i |= (uint32_t)buf[3];
Bu kod aslında tek satır olarak şöyle de yazılabilir.
i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);
Örnek
Şöyle yaparız.
uint8_t* buf = any address;

uint32_t val = 0;
uint32_t  b0 = buf[0];
uint32_t  b1 = buf[1];
uint32_t  b2 = buf[2];
uint32_t  b3 = buf[3];

val = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
Little Endian Gönder ve Al
Little Endian yazma ve okuma metodları gelmiyor. Mecburen kendimiz yazmalıyız.

Yazma
Şöyle yaparız. Buffer açısından bakarsak her zaman yazmaya MSB byte'tan başlarız. Yani Buffer'ın son alanından yazmaya başlarız. Belleği soldan sağa okuduğumuzu düşünürsek bu aslında byte'ların olduğu sırada gönderilmesi gibidir.
uint32_t i = ...;
uint8_t buf[4];
buf[3] = (i&0xff000000) >> 24;
buf[2] = (i&0x00ff0000) >> 16;
buf[1] = (i&0x0000ff00) >> 8;
buf[0] = (i&0x000000ff);
write(fd, buf, sizeof buf);

Okuma
Şöyle yaparız.
uint32_t i ;
uint8_t buf[4];
read(fd, buf, sizeof buf);
i  = (uint32_t)buf[3] << 24;
i |= (uint32_t)buf[2] << 16;
i |= (uint32_t)buf[1] << 8;
i |= (uint32_t)buf[0];
Bu kod aslında tek satır olarak şöyle de yazılabilir.
i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);





30 Aralık 2016 Cuma

Sistemin Endian Tipini Anlamak

Örnek 1 - byte pointer
Şöyle yaparız. Little Endian da yazmaya soldan başlayacağımız için ilk byte'a 1 yazılır. char'a cast edince de ilk byte 1 olarak gelir.
bool IsLittleEndian(){

  int a = 1;

  char* ptr = (char*)&a;

  return *ptr;
}
Örnek 2  - byte pointer
Şöyle yaparız.
int i = 7;
char* p = reinterpret_cast<char*>(&i);
if(p[0] == '\x7')
  std::cout << "This system is little-endian\n";
else
  std::cout << "This system is big-endian\n";
Çalışma şekli şudur.
Big endian:

+-----+-----+-----+-----+
|  0  |  0  |  0  |  7  |
+-----+-----+-----+-----+
   ^ pointer to int points here

Little endian:

+-----+-----+-----+-----+
|  7  |  0  |  0  |  0  |
+-----+-----+-----+-----+
   ^ pointer to int points here
Örnek 3 - byte pointer
Ya da şöyle bulunabilir. Big Endian da yazmaya sağdan başladığımız için ilk byte'a 0x01 yazılır. char'a cast edince de ilk byte 1 olarak gelir.
long test = 0x01020304;
char* ptr = (char*)&test;
int isSystemBigEndian = (ptr[0] == 0x01);
Örnek 4 - htons
Şöyle yaparız
#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
  uint16_t num = 123;

  if (htons(num) == num) {
    printf("big endian\n");
  } else {
    printf("little endian\n");
  }
}
Örnek 5 - union
byte pointer yöntemine benziyor. Şöyle yaparız
#include <stdio.h>
#include <stdint.h>

union echeck {
  uint32_t i;
  char c[4];
} echeck = { .c = { 0x01, 0x02, 0x03, 0x04 } };

int main()
{
  if (echeck.i == 0x01020304) {
    printf("big endian\n");
  } else if (echeck.i == 0x04030201) {
    printf("little endian\n");
  } else if (echeck.i == 0x02010403) {
    printf("pdp endian\n");
  } else {
    printf("other endian\n");
  }
  return 0;
}