Home > Back-end >  C4267 warning when trying to send data over socket in C
C4267 warning when trying to send data over socket in C

Time:07-06

My program will only run on Windows machines. I got multiple warnings, all the same. This is the warning:

Warning C4267   'argument': conversion from 'size_t' to 'int', possible loss of data

I get the warning when trying to send a string over a socket.

size_t ntohl_ch(char const* a)
{
    size_t x; memcpy(&x, a, sizeof(x));
    return ntohl(x);
}
size_t num = htonl(bufferSize); // bufferSize is also size_t

// Send buffer
    size_t totalSent = 0;
    size_t sent = 0;
    while (totalSent < bufferSize)
    {
        sent = send(ClientSocket, buffer   totalSent, bufferSize - totalSent, 0); // warning points to this line
        if (sent == SOCKET_ERROR)
        {
            printf("error sending buffer %d\n", WSAGetLastError());
            return SOCKET_ERROR;
        }
        totalSent  = sent;
    }

I know that send() return int and I can change sent and totalSent to int, but then inside send() I try to do operation like plus or minus on int and size_t. Like this: int - size_t. I don't think that's the right way to do it.

The warning doesn't show when I cast all the size_t parameters to int inside send(), but I think that's not the right way to do it because it can cause undefined behaviour. How can I solve this warning? Or can I just ignore it?

CodePudding user response:

That's not an important warning. Are you sure there isn't another one just below it which points out the actual bug?

No matter if using sys/socket.h or winsock2.h, the send function returns -1 (SOCKET_ERROR == -1) upon errors, as foretold in the Friendly Manual.

Therefore a correctly configured compiler such as gcc/mingw -Wall -Wextra tells you about this severe bug here if (sent == SOCKET_ERROR):

warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long long unsigned int'} and 'int' [-Wsign-compare]|

Since size_t can never have the value -1, this is a bug. Don't compare unsigned integers against negative values.


Instead of the bug, your compiler is apparently whining about some irrelevant stuff like passing size_t instead of int to the parameters.

From the Friendly Manual:

int WSAAPI send(
  [in] SOCKET     s,
  [in] const char *buf,
  [in] int        len,
  [in] int        flags
);

So just use int instead of size_t as told in the manual and all your problems will go away.

CodePudding user response:

The warning doesn't show when I cast all the size_t parameters to int inside send(), but I think that's not the right way to do it because it can cause undefined behaviour. How can I solve this warning? Or can I just ignore it?

There is only one parameter in the call to send() that you need to cast: the third. For that parameter, you are passing the result of the subtraction of one size_t from another, which will also be of size_t type.

However, as pointed out in the comments, so long as the resulting difference is less than INT_MAX (which seems likely, as that is 2147483647 on Windows), then you won't get any undefined behaviour from casting that result to an int. So, just cast the result of that subtraction to silence the warning.

But note: (as also pointed out in the comments), you also have an issue with the return value from that call. The SOCKET_ERROR constant is defined as (-1) in the "WinSock2.h" header, so testing an (unsigned) size_t value against that will, at best, confuse any future readers of your code1. It would be far better to have the sent variable declared as an int:

int sent = send(ClientSocket, buffer   totalSent, (int)(bufferSize - totalSent), 0);

1 This "confusion" can arise from trying to remember what the "usual arithmetic conversion" rules are when having integral operands of different signedness for the = and == operators. In your case, the size_t has an rank greater than (64-bit build) or equal to (32-bit build) the int 'literal' (-1), so (from the above-linked cppreference page):

If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type.

… further confusion could ensue, when trying to remember what the rule is for converting a negative integer to an unsigned type.

  • Related