fwrite() in C & readInt() in Java differ in endianess

4

Native Code :

writing number 27 using fwrite().

int main()
{
  int a = 27;
  FILE *fp;
  fp = fopen("/data/tmp.log", "w");
  if (!fp)
     return -errno;

  fwrite(&a, 4, 1, fp);
  fclose();
  return 0;
}

Reading back the data(27) using DataInputStream.readInt() :

public int readIntDataInputStream(void)
{
   String filePath = "/data/tmp.log";
   InputStream is = null;
   DataInputStream dis = null;
   int k;

   is = new FileInputStream(filePath);
   dis = new DataInputStream(is);
   k = dis.readInt();
   Log.i(TAG, "Size : " + k);
   return 0;
}

O/p

Size : 452984832

Well that in hex is 0x1b000000

0x1b is 27. But the readInt() is reading the data as big endian while my native coding is writing as little endian. . So, instead of 0x0000001b i get 0x1b000000.

Is my understanding correct? Did anyone came across this problem before?

java
android
c
endianness
datainputstream
asked on Stack Overflow Dec 9, 2016 by mk.. • edited Nov 20, 2017 by mk..

2 Answers

2

From the Javadoc for readInt():

This method is suitable for reading bytes written by the writeInt method of interface DataOutput

If you want to read something written by a C program you'll have to do the byte swapping yourself, using the facilities in java.nio. I've never done this but I believe you would read the data into a ByteBuffer, set the buffer's order to ByteOrder.LITTLE_ENDIAN and then create an IntBuffer view over the ByteBuffer if you have an array of values, or just use ByteBuffer#getInt() for a single value.

All that aside, I agree with @EJP that the external format for the data should be big-endian for greatest compatibility.

answered on Stack Overflow Dec 9, 2016 by Jim Garrison • edited Dec 9, 2016 by Jim Garrison
0

There are multiple issues in your code:

  • You assume that the size of int is 4, it is not necessarily true, and since you want to deal with 32-bit ints, you should use int32_t or uint32_t.

  • You must open the file in binary more to write binary data reliably. The above code would fail on Windows for less trivial output. Use fopen("/data/tmp.log", "wb").

  • You must deal with endianness. You are using the file to exchange data between different platforms that may have different native endianness and/or endian specific APIs. Java seems to use big-endian, aka network byte order, so you should convert the values on the C platform with the hton32() utility function. It is unlikely to have significant impact on performance on the PC side, as this function is usually expanded inline, possibly as a single instruction and most of the time will be spent waiting for I/O anyway.

Here is a modified version of the code:

#include <endian.h>
#include <stdint.h>
#include <stdio.h>

int main(void) {
    uint32_t a = hton32(27);
    FILE *fp = fopen("/data/tmp.log", "wb");
    if (!fp) {
        return errno;
    }
    fwrite(&a, sizeof a, 1, fp);
    fclose();
    return 0;
}
answered on Stack Overflow Dec 11, 2016 by chqrlie

User contributions licensed under CC BY-SA 3.0