如何处理“有符号/无符号不匹配”问题警告(C4018)?
我使用 c++ 编写的大量计算代码 考虑到高性能和低内存开销。它大量使用 STL 容器(主要是 std::vector
),并且几乎在每个函数中都会迭代该容器。
迭代代码如下所示:
for (int i = 0; i < things.size(); ++i)
{
// ...
}
但它会产生有符号/无符号不匹配警告(Visual Studio 中的 C4018)。
用一些 unsigned
类型替换 int
是一个问题,因为我们经常使用 OpenMP
编译指示,并且它要求计数器为 int
代码>.
我即将取消(数百个)警告,但恐怕我错过了一些解决该问题的优雅解决方案。
在迭代器上。我认为迭代器应用在适当的地方是很棒的。我正在使用的代码永远不会将随机访问容器更改为std::list
或其他东西(因此使用int i
进行迭代已经是与容器无关),并且总是需要当前索引。您需要输入的所有附加代码(迭代器本身和索引)只会使事情变得复杂并混淆底层代码的简单性。
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 std::vector
) a lot, and iterates over that containers almost in every single function.
The iterating code looks like this:
for (int i = 0; i < things.size(); ++i)
{
// ...
}
But it produces the signed/unsigned mismatch warning (C4018 in Visual Studio).
Replacing int
with some unsigned
type is a problem because we frequently use OpenMP
pragmas, and it requires the counter to be 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 never change random-access containers into std::list
or something (so iterating with int i
is already container agnostic), and will always need 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
一切都在您的
things.size()
类型中。它不是int
,而是size_t
(它存在于 C++ 中,而不是 C),它等于某种“常见”无符号类型,即unsigned int
代码> x86_32。运算符“less”(<) 不能应用于两个不同符号的操作数。只是没有这样的操作码,标准也没有指定编译器是否可以进行隐式符号转换。因此它只是将有符号数视为无符号数并发出该警告。
写得像这样
甚至更快是正确的
It's all in your
things.size()
type. It isn'tint
, butsize_t
(it exists in C++, not in C) which equals to some "usual" unsigned type, i.e.unsigned int
for 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.
It would be correct to write it like
or even faster
理想情况下,我会使用这样的构造:
这个 a 具有一个巧妙的优点,即您的代码突然变得与容器无关。
关于您的问题,如果您使用的某些库要求您使用
int
(其中unsigned int
更适合),那么它们的 API 很混乱。无论如何,如果您确定这些 int 始终为正,您可以这样做:这将向编译器清楚地指定您的意图:它不会再用警告来打扰您。
Ideally, I would use a construct like this instead:
This a has the neat advantage that your code suddenly becomes container agnostic.
And regarding your problem, if some library you use requires you to use
int
where anunsigned int
would better fit, their API is messy. Anyway, if you are sure that thoseint
are always positive, you may just do:Which will specify clearly your intent to the compiler: it won't bug you with warnings anymore.
如果您不能/不会使用迭代器,并且如果您不能/不会使用
std::size_t
作为循环索引,请创建.size()
到 int 转换函数,该函数记录假设并显式执行转换以消除编译器警告。然后你像这样编写循环:
这个函数模板的实例化几乎肯定会被内联。在调试版本中,将检查假设。在发布版本中,情况不会如此,并且代码将像直接调用 size() 一样快。这两个版本都不会产生编译器警告,并且只是对惯用循环进行了轻微修改。
如果您还想在发布版本中捕获假设失败,则可以将断言替换为 if 语句,该语句会引发
std::out_of_range("container size超出了 int 的范围")
之类的内容。请注意,这解决了有符号/无符号比较以及潜在的
sizeof(int)
!=sizeof(Container::size_type)
问题。您可以启用所有警告,并使用它们来捕获代码其他部分中的真正错误。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()
toint
conversion function that documents the assumption and does the conversion explicitly to silence the compiler warning.Then you write your loops like this:
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.
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")
.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.C++20 现在有
std::cmp_less
在 c++20constexpr 函数
>,我们在
中添加了
header,正是针对这种场景。这意味着,如果(由于某些有线原因)必须使用
i
作为int
eger,循环,并且需要与无符号整数进行比较,这是可以完成的:这也涵盖了这种情况,如果我们错误地
static_cast
将-1
(即int
)转换为unsigned int
。这意味着,以下内容不会给您带来错误:但是使用
std::cmp_less
将会C++20 has now
std::cmp_less
In c++20, we have the standard
constexpr
functionsadded in the
<utility>
header, exactly for this kind of scenarios.That means, if (due to some wired reasons) one must use the
i
asint
eger, the loops, and needs to compare with the unsigned integer, that can be done:This also covers the case, if we mistakenly
static_cast
the-1
(i.e.int
)tounsigned int
. That means, the following will not give you an error:But the usage of
std::cmp_less
will您可以使用:
例如:
You can use:
For example:
我还可以为 C++11 提出以下解决方案。
(C++对于auto p = 0不够聪明,所以我必须把p = 0U......)
I can also propose following solution for C++11.
(C++ is not smart enough for auto p = 0, so I have to put p = 0U....)
我会给你一个更好的想法
decltype
是因此,它推导出
things.size()
的类型,并且i
将是与things.size()
相同的类型。所以,<代码>我< things.size() 将在没有任何警告的情况下执行
I will give you a better idea
decltype
isSo, It deduces type of
things.size()
andi
will be a type as same asthings.size()
. So,i < things.size()
will be executed without any warning我有类似的问题。使用 size_t 不起作用。我尝试了另一种对我有用的方法。 (如下)
I had a similar problem. Using size_t was not working. I tried the other one which worked for me. (as below)
我只会做
I would just do