I am writing a socket client-server application where the server needs to send a large buffer to a client and all buffers should be processed separately, so I want to put the buffer length in the buffer so that the client can read the length of data from the buffer and process accordingly.
To put the length value I need to divide an integer value in one byte each and store it in a buffer to be sent over the socket. I am able to break the integer into four parts, but at the time of joining I am not able to retrieve the correct value. To demonstrate my problem I have written a sample program where I am dividing int into four char variables and then join it back in another integer. The goal is that after joining I should get the same result.
Here is my small program.
#include <stdio.h>
int main ()
{
int inVal = 0, outVal =0;
char buf[5] = {0};
inVal = 67502978;
printf ("inVal: %d\n", inVal);
buf[0] = inVal & 0xff;
buf[1] = (inVal >> 8) & 0xff;
buf[2] = (inVal >> 16) & 0xff;
buf[3] = (inVal >> 24) & 0xff;
outVal = buf[3];
outVal = outVal << 8;
outVal |= buf[2];
outVal = outVal << 8;
outVal |= buf[1];
outVal = outVal << 8;
outVal |= buf[0];
printf ("outVal: %d\n",outVal);
return 0;
}
inVal: 67502978 outVal: -126
What am I doing wrong?
There's no problem about size as both buffer need to be (and they are) of the same length. You cannot simply cast a character buffer to an int pointer, as the value will "consume" four character per int. Example: Based on this, the value p [0] will have it's data made up from the sizeof (int) / sizeof (char) = 4 first characters of buf.
In this article, we will discuss the C++ buffer in detail. In a normal scenario, a buffer gets created when a file is opened and buffer gets flushed when the file is closed. In C++ buffer can be created by the allocation of memory as shown below. Similarly, when the memory allocated has to be freed, the following format can be used.
storing values into the array of type char beyond the range of type char has implementation defined behavior: buf [0] = inVal & 0xff; and the next 3 statements ( inVal & 0xff might be larger than CHAR_MAX if char type is signed by default).
This is a C++ program that shows us the importance of clearing input buffer that can result in unwanted outputs. For this, first, import the libraries and then declare the integer and character variables. After that, write the code for getting the input and printing the values given as input.
One problem is that you are using bit-wise operators on signed numbers. This is always a bad idea and almost always incorrect. Please note that char
has implementation-defined signedness, unlike int
which is always signed.
Therefore you should replace int
with uint32_t
and char
with uint8_t
. With such unsigned types you eliminate the possibility of using bit shifts on negative numbers, which would be a bug. Similarly, if you shift data into the sign bits of a signed number, you will get bugs.
And needless to say, the code will not work if integers are not 4 bytes large.
Your method has potential implementation defined behavior as well as undefined behavior:
storing values into the array of type char
beyond the range of type char
has implementation defined behavior: buf[0] = inVal & 0xff;
and the next 3 statements (inVal & 0xff
might be larger than CHAR_MAX
if char
type is signed by default).
left shifting negative values invokes undefined behavior: if any of the 3 first bytes in the array becomes negative as the implementation defined result of storing a value larger than CHAR_MAX
into it, the resulting outVal
becomes negative, left shifting it is undefined.
In your specific example, your architecture uses 2's complement representation for negative values and the type char
is signed. The value stored into buf[0]
is 67502978 & 0xff = 130
, becomes -126
. The last statement outVal |= buf[0];
sets bits 7 through 31 of outVal
and the result is -126
.
You can avoid these issues by using an array of unsigned char
and values of type unsigned int
:
#include <stdio.h>
int main(void) {
unsigned int inVal = 0, outVal = 0;
unsigned char buf[4] = { 0 };
inVal = 67502978;
printf("inVal: %u\n", inVal);
buf[0] = inVal & 0xff;
buf[1] = (inVal >> 8) & 0xff;
buf[2] = (inVal >> 16) & 0xff;
buf[3] = (inVal >> 24) & 0xff;
outVal = buf[3];
outVal <<= 8;
outVal |= buf[2];
outVal <<= 8;
outVal |= buf[1];
outVal <<= 8;
outVal |= buf[0];
printf("outVal: %u\n", outVal);
return 0;
}
Note that the above code still assumes 32-bit ints.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With