禁止警告,由于常数为零,比较总是错误的

时间:2018-10-18 14:12:36

标签: c++ g++

我在本地项目中找到了这种形式的代码:

#include <iostream>

const unsigned LOWER_LIMIT = 0;

int main(int argc, char* argv[])
{
    if (argc > 1) {
        unsigned a = atoi(argv[1]);
        if (a < LOWER_LIMIT) {
        // if (a - LOWER_LIMIT > a) {
            std::cerr << "lower\n";
            a = LOWER_LIMIT;
        }
    }
}

atoi()部分仅用于演示的可运行性,并且在实际情况下由软件的其他部分提供。自然地,这段代码会产生一个警告,显示最近的g++ -Wall -Wextra

comparison of unsigned expression < 0 is always false

维护者不希望更改比较,因为常量LOWER_LIMIT将来可能会更改,并且他希望它可以不更改地继续工作。另外,他还希望该类型也为无符号。我抑制警告的第一个想法是

if (a - LOWER_LIMIT > a) {

使用未签名的下溢。但是对于某些人来说,这种解决方案有些难以理解。我找到了另一种解决方案:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
if (a < LOWER_LIMIT) {
#pragma GCC diagnostic pop

这可行,但是我从GCC部分假定这不是便携式解决方案。

是否存在一种可移植,通用且易于理解的方法来避免出现此警告,并且仍使某些开发人员能够简单地更改常量,而不必了解正在进行比较的代码库的这一部分?

编辑:我对此有一个模板解决方案,但感觉有点过头了:

template<typename NumericTypeA, typename NumericTypeB>
typename std::enable_if<std::is_unsigned<NumericTypeA>::value &&
            std::is_unsigned<NumericTypeB>::value, bool >::type
is_smaller_than(NumericTypeA a, NumericTypeB b)
{
    return (a - b > a);
}

template<typename NumericTypeA, typename NumericTypeB>
typename std::enable_if<std::is_signed<NumericTypeA>::value &&
            std::is_signed<NumericTypeB>::value, bool >::type
is_smaller_than(NumericTypeA a, NumericTypeB b)
{
    return (a < b);
}

编辑2:如果编译器检测到比较始终为假,则不必检查以下语句并确定这是可以的(在响应中也建议) ?

if ((LOWER_LIMIT > 0) && (a < LOWER_LIMIT)) {

感觉编译器应该在没有警告的情况下接受它,但是不幸的是,在这种情况下它确实会发出警告。

3 个答案:

答案 0 :(得分:2)

  

有便携式的#pragma吗?

不。 #pragma是根据定义实现定义的。

特别是警告选项在编译器之间千差万别。

  

维护者不想要...

由于涉及到维护人员,因此我认为所讨论的代码在第三方提供的包含的标头中。

您可以将编译器配置为不报告来自第三方标头的警告。对于GCC,可以使用-isystem选项代替-I。这样,您不必担心他们的警告。

如果要支持多个平台,则可能需要使用跨平台构建系统生成器,例如cmake。在cmake中,您可以使用SYSTEM选项指定系统包含目录-尽管并非所有系统都必须支持此概念。

答案 1 :(得分:2)

可能有一些方法可以解决带有额外层的编译器检查:

if (std::less<>()(a, LOWER_LIMIT)) // extra function

可能是模板的过度杀伤力:

template <std::size_t Limit>
struct DoesIfLess
{
    template <typename F>
    void operator ()(std::size_t a, F&&f) {
        if (a < Limit) {
            std::forward<F>(f)();
        }
    }
};

template <>
struct DoesIfLess<0>
{
    template <typename F>
    void operator ()(std::size_t, F&&) {}
};

然后

DoesIfLess<LOWER_LIMIT>(a, [&](){std::cerr << "lower\n"; a = LOWER_LIMIT; });

或使用C ++ 17

if constexpr (LOWER_LIMIT != 0) {
    if (a < LOWER_LIMIT) {
        std::cerr << "lower\n";
        a = LOWER_LIMIT;
    }
}

答案 2 :(得分:2)

如果将常量包装在仅返回常量值的不执行任何操作的函数中,警告将消失。

#include <iostream>

const unsigned LOWER_LIMIT = 0;

constexpr auto get_lower_limit() { return LOWER_LIMIT; }

int main(int argc, char* argv[])
{
    if (argc > 1) {
        unsigned a = atoi(argv[1]);

        if (a < get_lower_limit()) {
            std::cerr << "lower\n";
            a = LOWER_LIMIT;
        }
    }
}