C++ 如何处理“签名/未签名不匹配”警告 (C4018)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7443222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I deal with "signed/unsigned mismatch" warnings (C4018)?
提问by Andrew T
I work with a lot of calculation code written in C++ with high performance and low memory overhead in mind. It uses STL containers (mostly vector
) a lot, and iterates over that containers almost in every single function.
我使用了大量用 C++ 编写的计算代码,并考虑到了高性能和低内存开销。它大量使用 STL 容器(主要是vector
),并且几乎在每个函数中迭代这些容器。
The iterating code looks like this:
迭代代码如下所示:
for (int i = 0; i < things.size(); ++i)
{
// ...
}
but it produces the signed/unsigned mismatchwarning (C4018 in Visual Studio).
但它会产生有符号/无符号不匹配警告(Visual Studio 中的 C4018)。
Replacing int
with some unsigned
type is a problem because we frequently use OpenMP pragmas, and it requires the counter to be int
.
int
用某种unsigned
类型替换是一个问题,因为我们经常使用 OpenMP 编译指示,并且它要求计数器为int
.
I'm about to suppress the (hundreds of) warnings, but I'm afraid I've missed some elegant solution to the problem.
我即将取消(数百个)警告,但恐怕我错过了一些优雅的问题解决方案。
On iterators. I think iterators are great when applied in appropriate places. The code I'm working with will neverchange random-access containers into list
or something (so iterating with int i
is already container agnostic), and will alwaysneed the current index. And all the additional code you need to type (iterator itself and the index) just complicates matters and obfuscates the simplicity of the underlying code.
在迭代器上。我认为迭代器在适当的地方应用时很棒。我正在使用的代码永远不会将随机访问容器更改为list
或其他内容(因此迭代int i
已经与容器无关),并且将始终需要当前索引。您需要键入的所有附加代码(迭代器本身和索引)只会使问题复杂化并混淆底层代码的简单性。
回答by Andrew T
It's all in your things.size()
type. It isn't int
, but size_t
(it exists in C++, not in C) which equals to some "usual" unsigned type, i.e. unsigned int
for x86_32.
这一切都在你的things.size()
类型中。它不是int
,但是size_t
(它存在于 C++ 中,而不是在 C 中)它等于一些“通常的”无符号类型,即unsigned int
x86_32。
Operator "less" (<) cannot be applied to two operands of different sign. There's just no such opcodes, and standard doesn't specify, whether compiler can make implicit sign conversion. So it just treats signed number as unsigned and emits that warning.
运算符“less” (<) 不能应用于两个不同符号的操作数。只是没有这样的操作码,并且标准没有指定编译器是否可以进行隐式符号转换。所以它只是将有符号数视为无符号数并发出该警告。
It would be correct to write it like
像这样写是正确的
for (size_t i = 0; i < things.size(); ++i) { /**/ }
or even faster
甚至更快
for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }
回答by ereOn
Ideally, I would use a construct like this instead:
理想情况下,我会使用这样的构造:
for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i)
{
// if you ever need the distance, you may call std::distance
// it won't cause any overhead because the compiler will likely optimize the call
size_t distance = std::distance(things.begin(), i);
}
This a has the neat advantage that your code suddenly becomes container agnostic.
这 a 有一个巧妙的优势,即您的代码突然变得与容器无关。
And regarding your problem, if some library you use requires you to use int
where an unsigned int
would better fit, their API is messy. Anyway, if you are sure that those int
are always positive, you may just do:
关于您的问题,如果您使用的某些库要求您int
在unsigned int
更适合的地方使用,那么他们的 API 是混乱的。无论如何,如果您确定这些int
总是积极的,您可以这样做:
int int_distance = static_cast<int>(distance);
Which will specify clearly your intent to the compiler: it won't bug you with warnings anymore.
这将清楚地说明您对编译器的意图:它不会再用警告来打扰您。
回答by Adrian McCarthy
If you can't/won't use iterators and if you can't/won't use std::size_t
for the loop index, make a .size()
to int
conversion function that documents the assumption and does the conversion explicitly to silence the compiler warning.
如果您不能/不会使用迭代器,并且如果您不能/不会使用std::size_t
循环索引,请创建一个.size()
toint
转换函数来记录假设并明确进行转换以消除编译器警告。
#include <cassert>
#include <cstddef>
#include <limits>
// When using int loop indexes, use size_as_int(container) instead of
// container.size() in order to document the inherent assumption that the size
// of the container can be represented by an int.
template <typename ContainerType>
/* constexpr */ int size_as_int(const ContainerType &c) {
const auto size = c.size(); // if no auto, use `typename ContainerType::size_type`
assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
return static_cast<int>(size);
}
Then you write your loops like this:
然后你写你的循环是这样的:
for (int i = 0; i < size_as_int(things); ++i) { ... }
The instantiation of this function template will almost certainly be inlined. In debug builds, the assumption will be checked. In release builds, it won't be and the code will be as fast as if you called size() directly. Neither version will produce a compiler warning, and it's only a slight modification to the idiomatic loop.
这个函数模板的实例化几乎肯定会被内联。在调试版本中,将检查假设。在发布版本中,它不会,并且代码会像直接调用 size() 一样快。两个版本都不会产生编译器警告,并且只是对惯用循环的轻微修改。
If you want to catch assumption failures in the release version as well, you can replace the assertion with an if statement that throws something like std::out_of_range("container size exceeds range of int")
.
如果您还想在发布版本中捕获假设失败,您可以用 if 语句替换断言,该语句抛出类似std::out_of_range("container size exceeds range of int")
.
Note that this solves both the signed/unsigned comparison as well as the potential sizeof(int)
!= sizeof(Container::size_type)
problem. You can leave all your warnings enabled and use them to catch real bugs in other parts of your code.
请注意,这解决了有符号/无符号比较以及潜在的sizeof(int)
!=sizeof(Container::size_type)
问题。您可以启用所有警告,并使用它们来捕获代码其他部分中的真正错误。
回答by Adrian McCarthy
You can use:
您可以使用:
- size_t type, to remove warning messages
- iterators + distance (like are first hint)
- only iterators
- function object
- size_t 类型,删除警告信息
- 迭代器 + 距离(就像是第一个提示)
- 只有迭代器
- 功能对象
For example:
例如:
// simple class who output his value
class ConsoleOutput
{
public:
ConsoleOutput(int value):m_value(value) { }
int Value() const { return m_value; }
private:
int m_value;
};
// functional object
class Predicat
{
public:
void operator()(ConsoleOutput const& item)
{
std::cout << item.Value() << std::endl;
}
};
void main()
{
// fill list
std::vector<ConsoleOutput> list;
list.push_back(ConsoleOutput(1));
list.push_back(ConsoleOutput(8));
// 1) using size_t
for (size_t i = 0; i < list.size(); ++i)
{
std::cout << list.at(i).Value() << std::endl;
}
// 2) iterators + distance, for std::distance only non const iterators
std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end();
for ( ; itDistance != endDistance; ++itDistance)
{
// int or size_t
int const position = static_cast<int>(std::distance(list.begin(), itDistance));
std::cout << list.at(position).Value() << std::endl;
}
// 3) iterators
std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end();
for ( ; it != end; ++it)
{
std::cout << (*it).Value() << std::endl;
}
// 4) functional objects
std::for_each(list.begin(), list.end(), Predicat());
}
回答by Stepan Yakovenko
I can also propose following solution for C++11.
我还可以为 C++11 提出以下解决方案。
for (auto p = 0U; p < sys.size(); p++) {
}
(C++ is not smart enough for auto p = 0, so I have to put p = 0U....)
(C++ 对自动 p = 0 不够聪明,所以我必须把 p = 0U ....)
回答by Daniel kim
I will give you a better idea
我会给你一个更好的主意
for(decltype(things.size()) i = 0; i < things.size(); i++){
//...
}
decltype
is
decltype
是
Inspects the declared type of an entity or the type and value category of an expression.
检查实体的声明类型或表达式的类型和值类别。
So, It deduces type of things.size()
and i
will be a type as same as things.size()
. So,
i < things.size()
will be executed without any warning
因此,它推导出类型 ofthings.size()
并且i
将是与 相同的类型things.size()
。所以,
i < things.size()
将在没有任何警告的情况下执行
回答by Karthik_elan
I had a similar problem. Using size_t was not working. I tried the other one which worked for me. (as below)
我有一个类似的问题。使用 size_t 不起作用。我尝试了另一种对我有用的方法。(如下)
for(int i = things.size()-1;i>=0;i--)
{
//...
}
回答by Don Larynx
I would just do
我只会做
int pnSize = primeNumber.size();
for (int i = 0; i < pnSize; i++)
cout << primeNumber[i] << ' ';