gcc 如何在C和C++中比较不同大小的无符号整数时获得警告?

u5rb5r59  于 2023-08-06  发布在  其他
关注(0)|答案(2)|浏览(125)

C或C++中常见的bug来源是

size_t n = // ...

for (unsigned int i = 0; i < n; i++) // ...

字符串
unsigned int溢出时,其可以无限循环。
例如,在Linux上,unsigned int是32位的,而size_t是64位的,所以如果n = 5000000000,我们得到一个无限循环。
我如何使用GCC或clang获得关于此的警告?
GCC的-Wall -Wextra不能做到这一点:

#include <stdint.h>

void f(uint64_t n)
{
    for (uint32_t i = 0; i < n; ++i) {
    }
}
gcc-13 -std=c17 \
       -Wall -Wextra -Wpedantic \
       -Warray-bounds -Wconversion \
       -fanalyzer \
       -c -o 76840686.o 76840686.c

的数据
(no输出)

wwodge7n

wwodge7n1#

对于C++,你甚至可以做得比编译器警告更好,假设n是编译时常量。这也适用于非gcc编译器。但这种逻辑不适用于C代码。
这个想法基本上是在变量类型中编码值信息,而不是变量值。

template<std::integral T, auto N>
constexpr bool operator<(T value, std::integral_constant<decltype(N), N>)
{
    static_assert(std::is_signed_v<T> == std::is_signed_v<decltype(N)>, "the types have different signs");
    static_assert((std::numeric_limits<T>::max)() >= N, "the maximum of type T is smaller than N");
    return value < N;
}

// todo: overload with swapped operator parameter types

int main()
{
    constexpr std::integral_constant<size_t, 500'000'000> n; // go with 5'000'000'000, and you'll get a compiler error 

    for (unsigned int i = 0; i < n; i++)
    {

    }
}

字符串
如果该值不是编译时常量,您仍然可以为整数创建 Package 器模板类型,并重载<运算符以与整数值进行比较,将static_assert s添加到该运算符的主体中。

template<std::integral T>
class IntWrapper
{
    T m_value;
public:
    constexpr IntWrapper(T value)
        : m_value(value)
    {}

    template<std::integral U>
    friend constexpr bool operator<(U o1, IntWrapper o2)
    {
        static_assert(std::is_signed_v<U> == std::is_signed_v<T>, "types have different signedness");
        static_assert((std::numeric_limits<U>::max)() >= (std::numeric_limits<T>::max)(),
            "the comparison may never yield false because of the maxima of the types involved");

        return o1 < o2.m_value;
    }
};

void f(IntWrapper<uint64_t> n)
{
    for (uint32_t i = 0; i < n; ++i) {
    }
}


请注意,更改比较运算符的操作数之一的类型的必要性既有好处也有缺点:它要求你修改代码,但它也允许你在每个变量的基础上应用检查…

jchrr9hc

jchrr9hc2#

用于此目的的gcc seem to support-Warith-conversion的最新版本:
-Warith-conversion
即使将操作数转换为相同类型不能更改其值,也要对算术运算的隐式转换发出警告。这会影响来自-Wconversion-Wfloat-conversion-Wsign-conversion的警告。

void f (char c, int i)
{
    c = c + i; // warns with -Wconversion
    c = c + 1; // only warns with -Warith-conversion
}

字符串
但它不适用于your example

相关问题