jwm
jwm

Reputation: 1844

What is the least intrusive way to silence a signed/unsigned warning in C++?

I have a socket communication program. The protocol is that any error in writing is fatal, so the connection should be closed. My I/O code looks like this:

auto const toWrite = buf.size() * sizeof(buf[0]);
auto nWritten = ::write(fd, buf.data, toWrite);

if (toWrite != nWritten)
{
    closeTheSocket();
}

This code gives warning: comparison between signed and unsigned integer expressions on the boolean test.

I understand the evils of greater/less comparisons on signed vs unsigned, but it's unavoidable here. The signature for the ::write system call is

  #include <unistd.h>

  ssize_t write(int fd, const void *buf, size_t count);

In other words, my toWrite variable is properly unsigned and the returned nWritten is signed (-1 indicates an error). I don't care; anything other than complete transfer is fatal to the connection. Also, I don't understand how an (in)equality test between signed/unsigned could be dangerous.

I've looked here, here, here, and here, but the questions are all about less-than comparisons, and the answers are all "don't do that".

This question asks about silencing the warning, but a sledgehammer "silence all signed/unsigned" comparisons is undesirable.

How should I silence just this warning in the least intrusive manner possible?

Upvotes: 0

Views: 200

Answers (2)

Bob__
Bob__

Reputation: 12769

If you can bare some template boilerplate, another possible solution is to write a function which treats each type in a different way:

#include <type_traits>

template <class A, class B>
constexpr bool are_different(A a, B b)
{
    if constexpr (std::is_signed_v<A> and std::is_unsigned_v<B>)
    {
        if ( a < 0 )
            return true;
        else
            return std::make_unsigned_t<A>(a) != b;
    }
    else if constexpr (std::is_unsigned_v<A> and std::is_signed_v<B>)
    {
        if ( b < 0 )
            return true;
        else
            return a != std::make_unsigned_t<B>(b);
    }
    else
    {
        return a != b;
    }
}

int main()
{
    static_assert(are_different(1, 2));
    static_assert(!are_different(1ull, 1));
    static_assert(are_different(1, 2));
    static_assert(are_different(1u, 2));
    static_assert(are_different(1, 2u));
    static_assert(are_different(-1, -1u));
    static_assert(!are_different((long long)-1u, -1u));
}

Upvotes: 1

Separate the detection of the error condition from the detection of a incorrect length and use an explicit cast

if ( nWritten < 0 ||
     static_cast<decltype(toWrite)>(nWritten) != toWrite )
{
   // handle problems
}

Small edit: capture all negative values as errors for a wee bit of futureproofing.

Upvotes: 4

Related Questions