RobotRock
RobotRock

Reputation: 4459

Sending Java int to C over TCP

I'm trying to send Java's signed integers over TCP to a C client.

At the Java side, I write the integers to the outputstream like so:

static ByteBuffer wrapped = ByteBuffer.allocateDirect(4); // big-endian by default

public static void putInt(OutputStream out, int nr) throws IOException {
    wrapped.rewind();
    wrapped.putInt(nr);
    wrapped.rewind();

    for (int i = 0; i < 4; i++)
        out.write(wrapped.get());
}

At the C side, I read the integers like so:

int cnt = 0;
char buf[1];
char sizebuf[4];
while(cnt < 4) {
      iResult = recv(ConnectSocket, buf, 1, 0);
      if (iResult <= 0) continue;

      sizebuf[cnt] = buf[0];
      cnt++;
}

However, how do I convert the char array to an integer in C?

Edit

I have tried the following (and the reverse):

int charsToInt(char* array) {
     return (array[3] << 24) | (array[2] << 16) | (array[1] << 8) | array[0];   
}

Edited again, because I forgot the tags.

Data

For example of what happens currently:

I receive:

char 0
char 0
char 12
char -64
the int becomes 2448

and use the function for creating the int from the char array:

int charsToInt(char* array) {
    return ntohl(*((int*) array)); 
}

I expect the signed integer: 3264

Update I will investigate more after some sleep..

Update I have a Java client which interprets the integers correctly and receives the exact same bytes:

0
0
12
-64

Upvotes: 0

Views: 247

Answers (3)

Carl Norum
Carl Norum

Reputation: 224904

That depends on endianness, but you want either:

 int x = sizebuf[0] + 
         (sizebuf[1] << 8) +
         (sizebuf[2] << 16) +
         (sizebuf[3] << 24);

or:

 int x = sizebuf[3] + 
         (sizebuf[2] << 8) +
         (sizebuf[1] << 16) +
         (sizebuf[0] << 24);

Note that sizebuf needs to have an unsigned type for this to work correctly. Otherwise you need to mask off any sign-extended values you don't want:

 int x = (sizebuf[3] & 0x000000ff) + 
         ((sizebuf[2] << 8) & 0x0000ff00) +
         ((sizebuf[1] << 16) & 0x00ff0000) +
         ((sizebuf[0] << 24) & 0xff000000);

Upvotes: 1

fge
fge

Reputation: 121710

The classical C library has the method you want already, and it is independent from the machine endianness: ntohl!

// buf is a char */uint8_t *
uint32_t from_network = *((uint32_t *) buf);
uint32_t ret = ntohl(from_network);

This, and htonl for the reverse etc expect that the "network order" is big endian.

(the code above presupposes that buf has at least 4 bytes; the return type, and argument type, of ntohl and htonl are uint32_t; the JLS defines an int as 4 bytes so you are guaranteed the result)

Upvotes: 1

AlexisBRENON
AlexisBRENON

Reputation: 3079

To convert you char array, one possibility is to cast it to int* and to store the result :

int result = *((int*) sizebuf)

This is valid and one line. Other possibility is to compute integer from chars.

for (i = 0 ; i < 4; i++) 
     result = result << sizeof(char) + buf[0]

Choose the one that you prefer.

Alexis.

Edit : sizeof(char) is 1 because sizeof return a Byte result. So the right line is : result = result << (sizeof(char) * 8) + buf[0]

Upvotes: 0

Related Questions