1

のような文字列が 1 つあり"01030920316"ます。この文字列をロングに変換してからバイトに変換すると、Javaの出力の下に表示されます

output in java : Tag in bytes :  0, 0, 0, 0, 61, 114, -104, 124

この出力を取得したときにCで行うのと同じこと

output in C : Tag in bytes : 124,152,114,61,0,0,0,0

-104 and 152ここで、符号付きと符号なしの違いを理解していますが、最初は Java で、最後は C で 0 になるのはなぜですか。この動作のために、このバイトが検証のために C プログラム側に送られるときに問題が発生します。

問題が発生する場所を教えてください。

Java プログラム :

final byte[] tagBytes = ByteBuffer.allocate(8)
                .putLong(Long.parseLong("01030920316")).array();
System.out.println("Tag in bytes  >> " + Arrays.toString(tagBytes));

C プログラム :

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

/** To access long long values as a byte array*/
typedef union uInt64ToByte__
{
    uint64_t m_Value;
    unsigned char m_ByteArray[8];

}uInt64ToByte;

int main()
{
    uInt64ToByte longLongToByteArrayUnion;
    longLongToByteArrayUnion.m_Value = atoll("01030920316");
    printf("%d,%d,%d,%d,%d,%d,%d,%d",longLongToByteArrayUnion.m_ByteArray[0],longLongToByteArrayUnion.m_ByteArray[1],longLongToByteArrayUnion.m_ByteArray[2],longLongToByteArrayUnion.m_ByteArray[3],longLongToByteArrayUnion.m_ByteArray[4],longLongToByteArrayUnion.m_ByteArray[5],longLongToByteArrayUnion.m_ByteArray[6],longLongToByteArrayUnion.m_ByteArray[7]);
    return 0;
}
4

6 に答える 6

14

Java での出力: バイト単位のタグ: 0、0、0、0、61、114、-104、124

Java の ByteBuffer はデフォルトでビッグ エンディアンであり、そのバイトは署名されているため、127 より大きいバイトは負の値として表示されます。

C での出力: バイト単位のタグ: 124,152,114,61,0,0,0,0

C の配列は、x86/x64 システムではリトル エンディアンであるネイティブ バイト エンディアンを使用します。のunsigned char範囲は 0 ~ 255 です。

JavaでCと同じ出力を生成するには、次のことができます

final byte[] tagBytes = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder())
        .putLong(Long.parseLong("01030920316")).array();
int[] unsigned = new int[tagBytes.length];
for (int i = 0; i < tagBytes.length; i++)
    unsigned[i] = tagBytes[i] & 0xFF;
System.out.println("Tag in bytes  >> " + Arrays.toString(unsigned));

版画

Tag in bytes  >> [124, 152, 114, 61, 0, 0, 0, 0]
于 2013-01-03T15:40:45.117 に答える
4

Java と C では文字列の格納方法が異なるだけです。C で記述されたアプリケーションはネイティブであり、Java アプリケーションは Java 仮想マシンで実行されることを覚えておく必要があります。Java バイト コードはプラットフォームに依存しないため、Java コードはすべてのオペレーティング システム/プロセッサ アーキテクチャで同じように動作します。一方、格納された文字の順序は C では異なる場合があります (編集:異なるアーキテクチャで)

Edit2: 1101101 バイナリである数値 109 があるとしましょう。なんで?1 * 64 + 1 * 32 + 0 * 16 + 1 * 8 + 1 * 4 + 0 * 2 + 1 * 1 = 109. 最も左のビットは、重みが最大であるため、「最上位」と呼ばれます (2^ 6 = 64) であり、最も右のビットは重みが最小 (1 のみ) であるため、「最下位」と呼ばれます。109 は 1 バイトで格納できるため、かなり退屈です。00000011 11101000 バイナリである 1000 のような大きなものがあると仮定しましょう。2 バイト (X と Y としましょう) で格納されます。これで、その数値を XY (ビッグ エンディアン) または YX (リトルエンディアン) として保存できます。ビッグ エンディアンでは、最初のバイト (最下位アドレス) が最上位バイトです。リトルエンディアンでは、最初のバイトが最下位バイトです。x86 はリトル エンディアンで、JVM はビッグ エンディアンです。

于 2013-01-03T15:38:07.837 に答える
2

BigEndian と LittleEndianの違いです。

C++ で数値をバイト配列に変換すると、基になるシステムがビッグ エンディアン (マルチバイト整数の最上位バイトを最初に格納する) であるか、リトル エンディアン (最下位バイトを最初に格納する) であるかがわかります。

一方、Java は、常にビッグ エンディアンを使用することで、基になるシステムのエンディアンを隠します。これは、Java の「一度書けばどこでも実行できる」という哲学の一部です。

于 2013-01-03T15:42:13.420 に答える
0

C++ は、その型にネイティブ形式を使用します。Java は、Sparc のネイティブ形式に対応する標準定義形式を使用しますが、PC の形式とは異なります。

一般に、非文字型の場合、同じ値が含まれていても、2 つの異なるプラットフォームでバイトのダンプが同じであると想定する理由はありません。(プラットフォームによっては、サイズが同じでない場合もあります。C++ では 32、36、48、および 64 ビットの long を知っていますが、Java では常に 64 ビットです。)

于 2013-01-03T15:43:16.693 に答える
0

Java の整数の表現はプラットフォームに依存しないため、比較する際の参照として使用するので、C の整数の表現のプラットフォーム依存性を考慮した C コードを作成することをお勧めします。

これに続いて、OPに従ってバイト出力を作成するために次のCコードを提案します。

#define _BSD_SOURCE  

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

#if defined(__linux__)
#  include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#  include <sys/endian.h>
#elif defined(__OpenBSD__)
#  include <sys/types.h>
#  define be16toh(x) betoh16(x) /* -+ */
#  define be32toh(x) betoh32(x) /* -+--> not needed in this example */
#  define be64toh(x) betoh64(x) /* -+ */
#endif

int main()
{
  uint64_t uint64 = htobe64(atoll("01030920316")); /* convert to big endian/network byte order */

  for (int i = 0; i < sizeof(uint64); ++ i)
  {
    printf("%hhd, ", (signed char) (uint64 & 0xff));
    uint64 >>= 8;
  }

  printf("\n");

  return 0;
}
于 2013-01-03T18:23:21.587 に答える
0

まず、順序が逆に見える理由: これはputLong、class のメソッドがByteBuffer配列にバイトをビッグ エンディアンの順序で入れているためです。リトル エンディアンの順序で並べたい場合は、ByteBuffer で順序を設定します。

final byte[] tagBytes = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN)
        .putLong(Long.parseLong("01030920316")).array();

第二に、 C-104で得られるところに Java で入る理由152: それは、C では を使用してunsigned charおり、Java では型byteが unsigned ではなく signed であるためです。バイトの内容は実際には同じですが、符号付き整数として解釈した場合と、符号なし整数として解釈-104した場合を示して152います。

于 2013-01-03T15:44:03.737 に答える