C ++如何禁用具有不同符号变量比较的特定行的编译器警告?

Posted

技术标签:

【中文标题】C ++如何禁用具有不同符号变量比较的特定行的编译器警告?【英文标题】:C++ How to disable compiler warning for particular line with different signedness variables comparison? 【发布时间】:2018-05-24 18:50:56 【问题描述】:

我的 C++ 项目中有一个烦人的编译器警告。 它在一个模板函数中,它检查它的参数是否适合特定类型的范围,这被称为模板参数(在标准库中找不到它,它有吗?)。

我知道有符号与无符号整数类型的比较很棘手,因此我专门针对不同的有符号整数使用此函数,在有符号整数与无符号比较之前,我首先检查有符号整数是否为非负数。但是 gcc 会针对这种安全情况发出警告。 我不想用 -Wsign-compare 完全禁用这个警告,因为它很有用。 代码如下:

template <typename TRange, typename TSuspect, typename TCommonSignedness>
bool isInRangeOfHelper(const TSuspect & suspect,
                       const TCommonSignedness &,
                       const TCommonSignedness &)

    return std::numeric_limits<TRange>::min() <= suspect
         && suspect <= std::numeric_limits<TRange>::max();


template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect, 
                       const std::true_type &, 
                       const std::false_type &)

    return suspect <= std::numeric_limits<TRange>::max();


template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect, 
                        const std::false_type &, 
                        const std::true_type &)

    return 0 <= suspect 
           && suspect <= std::numeric_limits<TRange>::max();  // WARNING HERE



template <typename TRange, typename TSuspect>
bool isInRangeOf(const TSuspect & suspect)
    return isInRangeOfHelper<TRange>(suspect,
                           std::is_signed<TRange>(),
                           std::is_signed<TSuspect>());


template <typename TRange>
bool isInRangeOf(const TRange & suspect) return true; 



int main(int argc, char *argv[])

    if (!isInRangeOf<unsigned int>(-1))
        std::cout << "false";
     else 
        std::cout << "predicate error";
        std::terminate();
    
    return 0;

// warning: comparison of integer expressions of different signedness: 
// ‘const int’ and ‘unsigned int’ [-Wsign-compare]
// return 0 <= suspect && suspect <= std::numeric_limits<TRange>::max();
//                        ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

【问题讨论】:

使用演员表和评论。 @n.m.使用答案部分。 【参考方案1】:

一旦您验证了suspect 是非负数,您就可以安全地将其转换为其类型的无符号版本:

template <typename TRange, typename TSuspect>
bool isInRangeOfHelper(const TSuspect & suspect, 
                        const std::false_type &, 
                        const std::true_type &)

    return 0 <= suspect 
           && static_cast<std::make_unsigned_t<TSuspect>>(suspect) <= std::numeric_limits<TRange>::max();

[Live example]

【讨论】:

【参考方案2】:

代码前:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"

代码后:

#pragma GCC diagnostic pop

如果您想从宏扩展它以支持非 GCC 编译器,请使用等效的 _Pragma() 形式

边缘情况:

在旧版本的 GCC(4.6?文档没有说)中,这必须围绕函数,但现在可以在任何范围内完成。

如果您尝试在宏中隐藏警告,然后在同一个宏中触发它,则可能会出现问题。

某些编译器版本可能无法抑制关联的note:s 以进行某些诊断。

【讨论】:

【参考方案3】:

有几个选项:

1 UINT_MAX

isInRangeOf<unsigned int>( std::numeric_limits<unsigned_int>::max() );
isInRangeOf<unsigned int>( ​UINT_MAX );
// GCC specific
isInRangeOf<unsigned int>( __UINT32_MAX__ );

2 位技巧

isInRangeOf<unsigned int>( static_cast<unsigned int>(-1) )
isInRangeOf<unsigned int>( ~0 )
isInRangeOf<unsigned int>( 0xFFFFFFFF )

3 通过 pragma 指令抑制警告

(在进行一些模板元编程时,此选项对于一些未使用的参数警告很有用)

#ifdef __GNUG__
# define PUSH_IGNORE_WSIGN_CMP\
          _Pragma("GCC diagnostic push")\
          _Pragma("GCC diagnostic ignored \"-Wsign-compare\" ")
#  define POP_IGNORE_WSIGN_CMP _Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
#   define PUSH_IGNORE_WSIGN_CMP
            _Pragma("warning( push )")\
            _Pragma("warning( disable : C4018)")
#   define POP_IGNORE_WSIGN_CMP _Pragma("warning( pop )")
#endif

PUSH_IGNORE_WSIGN_CMP
    if (!isInRangeOf<unsigned int>(-1))
POP_IGNORE_WSIGN_CMP
        std::cout << "false";

【讨论】:

以上是关于C ++如何禁用具有不同符号变量比较的特定行的编译器警告?的主要内容,如果未能解决你的问题,请参考以下文章

3.C变量

如何在 C 中取消设置变量以允许稍后使用具有不同数据类型的相同名称?

C语言里符号常量和常变量有啥区别?

c语言定义常量define

如果C代码比较不同的数据类型,如何获得警告?

C ++如何从具有不同返回类型的接口多重继承?