Помощь с целью c - сдвиг байтов Java - PullRequest
0 голосов
/ 03 ноября 2010

Я отправляю данные между клиентами Java и iPhone / objC. Клиент Java имеет установленный компонент промежуточного программного обеспечения, который я использую для тестирования интеграции нового клиента с промежуточным программным обеспечением.

У меня проблема со всеми операциями сдвига байтов. Код Java находится в производстве и не может быть изменен. Поскольку дубль кажется самым обширным, я опубликую его.

Для отправки из objC:

-(void)putDouble:(NSNumber *)v{

    unsigned long long n = [v unsignedLongLongValue];

    dataToSend = [NSMutableData data];

    long long i = (int)n & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(n)]];


    i = ((int)n >> 8) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(n)]];


    i = ((int)n >> 16) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(n)]];


    i = ((int)n >> 24) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(n)]];


    i = ((int)n >> 32) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(i)]];


    i = ((int)n >> 40) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(i)]];


    i = ((int)n >> 48) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(i)]];


    i = ((int)n >> 56) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(i)]];
    [self send:dataToSend];

}

Java получает:

/*
 * Retrieve a double (64-bit) number from the stream.
 */
private double getDouble() throws IOException
{
    byte[] buffer = getBytes(8);

    long bits =
            ((long)buffer[0] & 0x0ff) |
            (((long)buffer[1] & 0x0ff) << 8) |
            (((long)buffer[2] & 0x0ff) << 16) |
            (((long)buffer[3] & 0x0ff) << 24) |
            (((long)buffer[4] & 0x0ff) << 32) |
            (((long)buffer[5] & 0x0ff) << 40) |
            (((long)buffer[6] & 0x0ff) << 48) |
            (((long)buffer[7] & 0x0ff) << 56);

    return Double.longBitsToDouble(bits);
}

Когда я отправляю [[WVDouble alloc] initWithDouble: -13456.134] из objC

Java получает двойной 5,53E-322

Проблема на стороне objC, так как Java работает в других средах разработки. Для всех производственных клиентов -13456.134 - конвертированный результат.

Вот код sendDouble, который использует клиент Java: `

 // Write a double (64-bit) number to the stream.

private void putDouble(double number) throws IOException
{
    long n = Double.doubleToLongBits(number);

    // have to write these in reverse order to be comptible

    stream.write((int)(n) & 0x0ff);
    stream.write((int)((n >>> 8)) & 0x0ff);
    stream.write((int)((n >>> 16)) & 0x0ff);
    stream.write((int)((n >>> 24)) & 0x0ff);
    stream.write((int)((n >>> 32)) & 0x0ff);
    stream.write((int)((n >>> 40)) & 0x0ff);
    stream.write((int)((n >>> 48)) & 0x0ff);
    stream.write((int)((n >>> 56)) & 0x0ff);
}

//--------------------------------------------------------------------------------

`

Ответы [ 3 ]

3 голосов
/ 03 ноября 2010

Как отметил @Vovanium, вы получаете длинное длинное значение типа double, которое в вашем примере вернет -13456. Без дроби, без показателя.

В ваших операциях сдвига и маски вы приводите к int слишком рано. Вам необходимо применить приведение после смены и маски. Кроме того, обертывание в цикле уменьшает монтирование кода для изменения.

int i;
int j;

for (j = 0; j < sizeof(n); j++) {
    i = (int)(n >> (j*8)) & 0x0ff;
    [dataToSend appendData:[NSMutableData dataWithBytes:&i length:sizeof(i)]];
}
[self send:dataToSend];

Обратите внимание, что, согласно JavaDocs для Double , Java ожидает, что биты будут иметь определенный порядок. Вы получите неправильные значения, если приведение от long к unsigned long long не произведет этот битовый порядок. В этом случае может потребоваться переставить биты перед отправкой.

Бит 63 (бит, выбранный маской 0x8000000000000000L) представляет знак числа с плавающей запятой. Биты 62-52 (биты, которые выбираются маской 0x7ff0000000000000L) представляют экспоненту. Биты 51-0 (биты, которые выбираются маской 0x000fffffffffffffL) представляют значение и (иногда называемое мантиссой) числа с плавающей запятой.

Обновление:

Убедитесь, что вы приняли изменение @ Vovanium, чтобы вы работали над правильным набором битов:

double nd = [v doubleValue];
unsigned long long n = *(long long *)&nd;

Попробуйте выполнить тестирование со значением -1,0. 754-битовый шаблон IEEE для -1.0:

0xbff0000000000000

А при сериализации байты будут

00 00 00 00 00 00 f0 bf

Если вместо этого вы получите эти байты:

bf f0 00 00 00 00 00 00

вы столкнулись с проблемой порядка байтов. Если это так, то вы изменил бы строку в моем примере кода на

    i = (int)(n >> ((sizeof(n) - j - 1)*8)) & 0x0ff;

Это просто меняет порядок, в котором декодируется длинный long.

2 голосов
/ 03 ноября 2010

Код ObjC передает битовую комбинацию длинного целого числа (полученную unsignedLongLongValue), которую Java-код пытается интерпретировать как битовую комбинацию double.Вы должны получить битовую комбинацию double, используя doubleValue, при доступе к нему как ULL.

double nd = [v doubleValue];
unsigned long long n = *(long long *)&nd;
1 голос
/ 06 ноября 2010

Если вы отправляете данные с sizeof (n) (8 байт) или sizeof (i) (4 байт), вам следует ожидать считывания 8 или 4 байтов не по одному за раз.Я подозреваю, что вместо этого вы намереваетесь отправлять по одному байту за раз, поэтому, возможно, тип данных должен быть байтом, а длина должна быть 1.

...