Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store an int in a char buffer in C and then retrieve the same

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;
}

Output

inVal: 67502978 outVal: -126

What am I doing wrong?

like image 219
Pratik Avatar asked Jan 11 '17 07:01

Pratik


People also ask

Can I cast a character buffer to an int pointer?

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.

How to create a C++ buffer?

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.

How do you store values in an array of char types?

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).

How do you clear the input buffer in C++?

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.


2 Answers

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.

like image 122
Lundin Avatar answered Oct 24 '22 09:10

Lundin


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.

like image 43
chqrlie Avatar answered Oct 24 '22 08:10

chqrlie