24 Mart 2016 Perşembe

Endian

Endian Nedir?
Endianness Nedir yazısına taşıdım

Sistemin Endian Tipini Anlamak
Sistemin Endian Tipini Anlamak yazısına taşıdım.

Big Endian'a Çevirerek Yazma
C
htonl veya htons ile verilen 32 bit veya 16 bitlik sayılar Big Endian'a çevirilebilir. Örnek:
uint32_t tmp = htonl(any32bitint);
send(socket, (char *) &tmp, sizeof(tmp), 0);
64'bitlik sayıları BigEndian'a çevirmek için aşağıdaki gibi yapılabilir.

int32_t data [2];
data[0] = htonl((int32_t) from);
data[1] = htonl((int32_t) (from >> 32));

int64_t mynum;
from = (int64_t) ntohl(data[1]);
from = (from << 32);
from = from | (int64_t) ntohl(data[0]);
C#
C#'ta BigEndian ile ilgili bir stream sınıfı yok. BinaryWriter sınıfından türeyen ve çok işe yarayan BEBinaryWriter sınıfı burada.

Java
DataOutputStream  
DataOutputStream yazısına taşıdım.

Big Endian'dan Okuma
C
ntohl veya ntohs ile verilen 32 veya 16 bitlik sayılar Big Endian'dan okunabilir. Bu fonksiyonlar unsigned döndürdükleri için, sonucu cast etmek gerekebilir.

ntohl
Şöyle kullanırız:
uint32_t data = ...;
int32_t value = (int32_t) ntohl(data);
Kendi ntohl gerçekleştirimimiz
ntolh'yi kendimiz yazmak isteseydik şöyle yapardık
char b[4] = //...

uint32_t result;
uchar *p = (uchar *)(&result);
*p++ = b[3];
*p++ = b[2];
*p++ = b[1];
*p     = b[0];
Ya da şöyle yapardık:
char* bp = ...;
*(uint32_t*)bp = (uint32_t)(
                (*bp       << 24) |
                (*(bp + 1) << 16) |
                (*(bp + 2) <<  8) |
                (*(bp + 3)      ));
Ya da şöyle yapardık. Bu kod ilk örnek ile aynı aslında.
long NTOHL(long value)
{

    long test = 0x01020304;
    char* ptr = (char*)&test;
    int isSystemAlreadyBigEndian = (ptr[0] == 0x01);

    char* ptrValue = (char*)&value;
    long result = value;
    char* ptrResult = (char*)&result;

    if (!isSystemAlreadyBigEndian)
    {
        // do the byte swap
        ptrResult[0] = ptrValue[3];
        ptrResult[1] = ptrValue[2];
        ptrResult[2] = ptrValue[1];
        ptrResult[3] = ptrValue[0];
    }

    return result;

}


8 byte'lık double okuma da benzer bir mantığa sahip.
char b[8] = //...

double result;
uchar *p = (uchar *)(&result);
*p++ = b[7];
*p++ = b[6];
*p++ = b[5];
*p     = b[4];
*p++ = b[3];
*p++ = b[2];
*p++ = b[1];
*p     = b[0];
C++ ile şöyle yaparız.
int64_t size;
recv(client, (char *)&size, sizeof int64_t, 0);
char *start = (char *)&size, *end = start + sizeof(size);
std::reverse(start, end);
Büyük Endian'dan küçük endian'a çevirmek için template ta kullanabiliriz. Örnek:


Java
ByteBuffer
getDouble
ByteBuffer sınıfının getDouble() vs. metodları ile BigEndian formatı okunabilir. Örnek:

flip
Bu konudan çok emin olmamakla beraber ByteBuffer herhangi bir mevcut buffer'ı wrap etse bile okumaya başlamadan önce fliıp() metodu ile okumaya hazır hale getirmek lazım.

network byte order to host byte order in java sorusunda verilen cevapta ByteBuffer sınıfı okumaya başlarken flip() metodu ile okumaya hazır hale getiriliyor.

flip() metodu aşağıdaki gibi kodlanmış ve amacı ise ByteBuffer sınıfına verilmiş olan limiti en son yazma pozisyonuna eşitlemek çünkü okuma işleminde sınıfın tamponunun sonuna gelip gelinmediği limit değerine bakarak kontrol ediliyor.


Yani netty ile ByteBuffer kullanmak için aşağıdakine benzer bir kod lazım.
ByteBuffer buf = ByteBuffer.allocate(1);
buf.put(0x1c);
buf.flip();//Okumaya hazırla
e.getChannel().write(ChannelBuffers.wrappedBuffer(buf));

DataInputStream
DataOutputStream ve DataInputStream yazısına taşıdım.

QT
QDataStream
QDataStream sınıfıyla ilgili olarak STL,StreamBuffer nesnesi ve QT başlıklı yazıya göz atabilirsiniz. QT ile QIODevice stream sınıflarının temeli gibi düşünülebilir. Qt serialization - how to exclude a field? sorusunda QDataStream sınıfı kullanılarak bir nesneyi binary olarak yazma örneği bulunabilir. Bu iş için aşağıdaki gibi operatörler tanımlamak yeterli.
friend operator << (QDataStream& stream, const MyClass& myclass)

Little Endian'dan Okuma
Java
ByteBuffer
order
Normalde JVM BigEndian çalışır ama Little Endian çalışılmak istenirse order metodu kullanılabilir. Örnek:
  
Integer.reverseBytes
Örnekte küçük endian'dan float okuma ve float yazma gösterilmiş.
Float.intBitsToFloat(Integer.reverseBytes(dataInputStream.readInt()));

C# 
BitConverter
BitConverter sınıfı ile LittleEndian veri okunabilir. 


ToUInt16

Örnek:
byte[] buffer = new byte[2];
ushort value = BitConverter.ToUInt16(buffer, 0);
Küçük Endian Yazma
Java
Örnekte küçük endian yazma gösterilmiş.
dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float)));

Hiç yorum yok:

Yorum Gönder