Trying to understand some C/C++ code

B

bufferOverflow

Greetings all,

I am trying to understand a piece of C++ code that I am trying to port
to Java.


void Buffer::packInteger(int value){

int netval = htonl(value); // convert to network order (big-endian)
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4
bytes to data

char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?

memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;
datalen += 4; //increment datalen by 4

}
Now if I understood the comments in the code correctly, I can't seem
to understand how the integer called "value" is being packed even at
all in the code above!

My stab of the code above in Java is something like this -

public void packInteger(int value) {
//b is defined as byte b[ ] = new byte[4];
b[0] = (byte) ((val >> 24) & 255);
b[1] = (byte) ((val >> 16) & 255);
b[2] = (byte) ((val >> 8) & 255);
b[3] = (byte) (val & 255);
}

AFAICT, the code above shifts 24,26,8 and 0 places to the right and
then ANDs it with 255 to get the values at those position
respectively. Is this how it's done ? Or am I missing some critical
pieces. I think I am. :-(

Thanks!
 
B

bufferOverflow

Greetings all,

I am trying to understand a piece of C++ code that I am trying to port
to Java.

void Buffer::packInteger(int value){

int netval = htonl(value); // convert to network order (big-endian)
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4
bytes to data

char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?

memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;
datalen += 4; //increment datalen by 4

}
Now if I understood the comments in the code correctly, I can't seem
to understand how the integer called "value" is being packed even at
all in the code above!

My stab of the code above in Java is something like this -

public void packInteger(int value) {
//b is defined as byte b[ ] = new byte[4];
b[0] = (byte) ((val >> 24) & 255);
b[1] = (byte) ((val >> 16) & 255);
b[2] = (byte) ((val >> 8) & 255);
b[3] = (byte) (val & 255);

Should be:
b[0] = (byte) ((value >> 24) & 255);
b[1] = (byte) ((value >> 16) & 255);
b[2] = (byte) ((value >> 8) & 255);
b[3] = (byte) (value & 255);
 
P

Patricia Shanahan

bufferOverflow said:
Greetings all,

I am trying to understand a piece of C++ code that I am trying to port
to Java.

void Buffer::packInteger(int value){

int netval = htonl(value); // convert to network order (big-endian)
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4
bytes to data

char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?

memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;
datalen += 4; //increment datalen by 4

}
Now if I understood the comments in the code correctly, I can't seem
to understand how the integer called "value" is being packed even at
all in the code above!

My stab of the code above in Java is something like this -

public void packInteger(int value) {
//b is defined as byte b[ ] = new byte[4];
b[0] = (byte) ((val >> 24) & 255);
b[1] = (byte) ((val >> 16) & 255);
b[2] = (byte) ((val >> 8) & 255);
b[3] = (byte) (val & 255);

Should be:
b[0] = (byte) ((value >> 24) & 255);
b[1] = (byte) ((value >> 16) & 255);
b[2] = (byte) ((value >> 8) & 255);
b[3] = (byte) (value & 255);

The overall function of the C code seems to be to append value,
expressed in network order, to a byte buffer, presumably for purposes of
output to a stream?

Is it possible to look at this another layer up in the code? Maybe all
you need is to attach a DataOutputStream to the output and use its
writeInt method?

Patricia
 
B

bufferOverflow

Hi Patricia and Roedy,

bufferOverflow said:
Greetings all,
I am trying to understand a piece of C++ code that I am trying to port
to Java.
void Buffer::packInteger(int value){
int netval = htonl(value); // convert to network order (big-endian)
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4
bytes to data
char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?
memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;
datalen += 4; //increment datalen by 4
}
Now if I understood the comments in the code correctly, I can't seem
to understand how the integer called "value" is being packed even at
all in the code above!
My stab of the code above in Java is something like this -
public void packInteger(int value) {
//b is defined as byte b[ ] = new byte[4];
b[0] = (byte) ((val >> 24) & 255);
b[1] = (byte) ((val >> 16) & 255);
b[2] = (byte) ((val >> 8) & 255);
b[3] = (byte) (val & 255);
Should be:
b[0] = (byte) ((value >> 24) & 255);
b[1] = (byte) ((value >> 16) & 255);
b[2] = (byte) ((value >> 8) & 255);
b[3] = (byte) (value & 255);

The overall function of the C code seems to be to append value,
expressed in network order, to a byte buffer, presumably for purposes of
output to a stream?

Yes, that's the end output.
The data buffer in Java code is b[].
In C++ code, it's the data.
Is it possible to look at this another layer up in the code? Maybe all
you need is to attach a DataOutputStream to the output and use its
writeInt method?

The writeInt() method writes the passed in "value" parameter to the
byte ? Maybe you were mean writeByte() ? If you meant writeInt(), this
isn't possible because down the wire, it has to be sent as individual
bytes.

The whole library's central piece is this buffer. I can't write to a
OutputStream just yet in here (as in a Socket), this whole writing-to-
Socket business is taken care of by a encoder/decoder working one
layer above this buffer class which takes care of things like encoding/
decoding the whole buffer (bytes [numbers,strings etc..]) to a stream
(socket).


Thanks for your input Patricia and Roedy but I think my concept is
going a bit crusty here. I'll get back when I understand what the heck
I am doing!
Thanks again.
 
N

Nigel Wade

bufferOverflow said:
Greetings all,

I am trying to understand a piece of C++ code that I am trying to port
to Java.


void Buffer::packInteger(int value){

int netval = htonl(value); // convert to network order (big-endian)
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4
bytes to data

char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?

memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;
datalen += 4; //increment datalen by 4

}
Now if I understood the comments in the code correctly, I can't seem
to understand how the integer called "value" is being packed even at
all in the code above!

It is converted to a network byte order integer netval. netval is "packed" using
memcpy to the end of the newly allocated storage area.
My stab of the code above in Java is something like this -

public void packInteger(int value) {
//b is defined as byte b[ ] = new byte[4];
b[0] = (byte) ((val >> 24) & 255);
b[1] = (byte) ((val >> 16) & 255);
b[2] = (byte) ((val >> 8) & 255);
b[3] = (byte) (val & 255);
}

AFAICT, the code above shifts 24,26,8 and 0 places to the right and
then ANDs it with 255 to get the values at those position
respectively. Is this how it's done ? Or am I missing some critical
pieces. I think I am. :-(

There should be no need to do this operation in Java. All integers are written
in network byte order, regardless of the hardware platform. It can be made into
a NOOP if you use an internal buffer and write the integer to it.
int netval = htonl(value); // convert to network order (big-endian)

not required, use ByteBuffer later to do it for us.
data = (char *) realloc(data, datalen + 4); //allocate datalen + 4

byte[] newData = new byte[data.length+4];
System.arraycopy(data,0,newData,0,data.length);
data = newData;
bytes to data

char* temp = data + datalen; //temp is allocated a pointer to (data
+datalen) ?

memcpy(temp, &netval, 4); // copy the first 4 bytes from netval to
temp;

Use a ByteBuffer to wrap the byte array, then we can use the byte ordered
methods to store the int in network byte order (the default ByteBuffer is
BIG_ENDIAN which is the same as network byte order).

ByteBuffer bb = ByteBuffer.wrap(data, datalen, 4);
bb.putInt(int);
datalen += 4; //increment datalen by 4

datalen = data.length;
 
L

Lew

bufferOverflow said:
The writeInt() method writes the passed in "value" parameter to the
byte ? Maybe you were mean writeByte() ? If you meant writeInt(), this
isn't possible because down the wire, it has to be sent as individual
bytes.

Isn't that exactly what writeInt() does?
 
P

Patricia Shanahan

bufferOverflow said:
Hi Patricia and Roedy, ....

The writeInt() method writes the passed in "value" parameter to the
byte ? Maybe you were mean writeByte() ? If you meant writeInt(), this
isn't possible because down the wire, it has to be sent as individual
bytes.

I find this remark rather confusing, because you seem to be telling me
that you cannot use writeInt because you need to do exactly what
DataOutputStream's writeInt does.
The whole library's central piece is this buffer. I can't write to a
OutputStream just yet in here (as in a Socket), this whole writing-to-
Socket business is taken care of by a encoder/decoder working one
layer above this buffer class which takes care of things like encoding/
decoding the whole buffer (bytes [numbers,strings etc..]) to a stream
(socket).

The data output stream could be based on a ByteArrayOutputStream.

Patricia
 
P

Patricia Shanahan

bugbear said:
^^^^^^^^^^^^^^^^^^^^^^^^^
This line is an appalling piece of C. It is CPU dependent, since
it takes the address of an integer, and treats it as a byte pointer.

It also assumes sizeof(int)==4. I suppose it's a change from all the
bad C code I saw in the 1980's that assumed sizeof(int)==2.

Patricia
 
S

shakah

^^^^^^^^^^^^^^^^^^^^^^^^^
This line is an appalling piece of C. It is CPU dependent, since
it takes the address of an integer, and treats it as a byte pointer.

Picking up the bytes, you'll get them in whatever order
your CPU uses, which is not defined in 'C'.

I will grant, there's some "implicit" documentation
in the call to htonl() and it's comment, which makes
the memcpy() stuff all the more odd.

Even coding in 'C' I would use code much more like
your "shift and mask" sequence, to ensure that my
code was portable.

I've been a full-time pro for too long to write
non-portable code, unless absolutely unavoidable.

Of course, in 'C' the preprocessor can be your friend
for portability and efficiency, since the CPU
type is known at compile time.

BugBear

So for portability you'd opt for your own "shift and mask" sequence in
place of the standard htonl()?

Also, while not checking the return value of realloc() and assuming
that sizeof(int)==4 (both in the temp storage for htonl()'s return
value and in the memcpy() call) are valid issues to raise, do you
really have a problem with the memcpy() as used in the above context?
On what platform do you think the particular code would be problematic?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top