客観的なC -Javaバイトシフトを手伝ってください
-
28-09-2019 - |
質問
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は2倍の5.53E-322を取得します
Javaは他の開発環境で生産されているため、問題はOBJC側にあります。すべての生産クライアントがいる-13456.134は変換された結果です。
これがJavaクライアントが使用するSendDoubleコードです: `
// 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);
}
//--------------------------------------------------------------------------------
`
解決
@vovaniumが指摘したように、あなたはダブルの長い長い値を得ています。例では-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, 、Javaは、ビットに特定の順序があると予想しています。ダブルから署名されていないロングまでキャストしても、そのビット順序が生成されない場合、誤った値が得られます。その場合、送信する前にビットを再配置する必要がある場合があります。
ビット63(マスク0x8000000000000000Lによって選択されるビット)は、フローティングポイント数の符号を表します。ビット62-52(マスク0x7ff000000000000000000Lによって選択されるビット)は、指数を表します。ビット51-0(マスク0x000fffffffffffffffで選択されたビット)は、フローティングポイント数の重要である(マンティッサとも呼ばれることもあります)を表します。
アップデート:
@vovaniumの変更を確認してください。
double nd = [v doubleValue];
unsigned long long n = *(long long *)&nd;
-1.0の値でテストを試してみてください。 -1.0のIEEE 754ビットパターンは次のとおりです。
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;
それは、長い長さがデコードされる順序を逆転させるだけです。
他のヒント
OBJCコードは、Javaコードがダブルのビットパターンとして解釈しようとする長い長い整数のビットパターン(unsignedlonglongValueによって得られます)を送信します。 DoubleValueを使用してDoubleのビットパターンを取得します。
double nd = [v doubleValue];
unsigned long long n = *(long long *)&nd;
sizeof(n)(8バイト)またはsizeof(i)(4バイト)でデータを送信する場合は、一度に1つでない8つまたは4バイトを読み取ることが期待されます。代わりに、一度に1つのバイトを送信するつもりだと思うので、おそらくデータ型はバイトでなければならず、長さは1でなければなりません。