C++ 使用 -1 将所有位设置为 true 是否安全?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/809227/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:23:03  来源:igfitidea点击:

Is it safe to use -1 to set all bits to true?

c++cbinarybit-fields

提问by hyperlogic

I've seen this pattern used a lot in C & C++.

我已经看到这种模式在 C 和 C++ 中被大量使用。

unsigned int flags = -1;  // all bits are true

Is this a good portable way to accomplish this? Or is using 0xffffffffor ~0better?

这是一个很好的便携方式来完成这个吗?或者是使用0xffffffff还是~0更好?

回答by Johannes Schaub - litb

I recommend you to do it exactly as you have shown, since it is the most straight forward one. Initialize to -1which will work always, independent of the actual sign representation, while ~will sometimes have surprising behavior because you will have to have the right operand type. Only then you will get the most high value of an unsignedtype.

我建议你完全按照你所展示的去做,因为它是最直接的。初始化到-1which 将始终有效,独立于实际的符号表示,而~有时会出现令人惊讶的行为,因为您必须拥有正确的操作数类型。只有这样,您才能获得unsigned类型的最高值。

For an example of a possible surprise, consider this one:

有关可能的惊喜的示例,请考虑以下示例:

unsigned long a = ~0u;

It won't necessarily store a pattern with all bits 1 into a. But it will first create a pattern with all bits 1 in an unsigned int, and then assign it to a. What happens when unsigned longhas more bits is that not all of those are 1.

它不一定会将所有位为 1 的模式存储到a. 但它会首先创建一个模式,所有位都为 1 unsigned int,然后将其分配给a。当unsigned long有更多位时发生的情况是,并非所有位都是 1。

And consider this one, which will fail on a non-two's complement representation:

并考虑这个,它将在非二进制补码表示上失败:

unsigned int a = ~0; // Should have done ~0u !

The reason for that is that ~0has to invert all bits. Inverting that will yield -1on a two's complement machine (which is the value we need!), but will notyield -1on another representation. On a one's complement machine, it yields zero. Thus, on a one's complement machine, the above will initialize ato zero.

原因是~0必须反转所有位。反转,将产生-1一个补台机器上(这是我们所需要的值!),但将不会产生-1对另一种表示。在一个补码机上,它产生零。因此,在补码机上,上述内容将初始化a为零。

The thing you should understand is that it's all about values - not bits. The variable is initialized with a value. If in the initializer you modify the bits of the variable used for initialization, the value will be generated according to those bits. The value you need, to initialize ato the highest possible value, is -1or UINT_MAX. The second will depend on the type of a- you will need to use ULONG_MAXfor an unsigned long. However, the first will not depend on its type, and it's a nice way of getting the most highest value.

你应该明白的是,这一切都是关于价值的——而不是比特。变量用一个初始化。如果在初始化程序中修改用于初始化的变量的位,则将根据这些位生成值。初始化a为可能的最高值所需的值是-1or UINT_MAX。第二个将取决于类型a- 您将需要ULONG_MAX用于unsigned long. 但是,第一个不依赖于它的类型,这是获得最高值的好方法。

We are nottalking about whether -1has all bits one (it doesn't always have). And we're nottalking about whether ~0has all bits one (it has, of course).

我们不是在谈论是否-1所有位都为 1(并非总是如此)。而且我们不是在谈论是否~0所有位都为一(当然,它有)。

But what we are talking about is what the result of the initialized flagsvariable is. And for it, only -1will work with every type and machine.

但是我们要讨论的是初始化flags变量的结果是什么。对于它,-1适用于所有类型和机器。

回答by Dingo

  • unsigned int flags = -1;is portable.
  • unsigned int flags = ~0;isn't portable because it relies on a two's-complement representation.
  • unsigned int flags = 0xffffffff;isn't portable because it assumes 32-bit ints.
  • unsigned int flags = -1;是便携式的。
  • unsigned int flags = ~0;不可移植,因为它依赖于二进制补码表示。
  • unsigned int flags = 0xffffffff;不可移植,因为它假定为 32 位整数。

If you want to set all bits in a way guaranteed by the C standard, use the first one.

如果要以 C 标准保证的方式设置所有位,请使用第一个。

回答by Doug T.

Frankly I think all fff's is more readable. As to the comment that its an antipattern, if you really care that all the bits are set/cleared, I would argue that you are probably in a situation where you care about the size of the variable anyway, which would call for something like boost::uint16_t, etc.

坦率地说,我认为所有 fff 都更具可读性。至于它是一个反模式的评论,如果你真的关心所有的位都被设置/清除,我会争辩说你可能处于一种你关心变量大小的情况,这需要像 boost 这样的东西::uint16_t 等

回答by hammar

A way which avoids the problems mentioned is to simply do:

避免上述问题的一种方法是简单地执行以下操作:

unsigned int flags = 0;
flags = ~flags;

Portable and to the point.

便携式和重点。

回答by Edouard A.

I am not sure using an unsigned int for flags is a good idea in the first place in C++. What about bitset and the like?

我不确定在 C++ 中首先使用 unsigned int 作为标志是一个好主意。bitset 之类的呢?

std::numeric_limit<unsigned int>::max()is better because 0xffffffffassumes that unsigned int is a 32-bit integer.

std::numeric_limit<unsigned int>::max()更好,因为0xffffffff假设 unsigned int 是一个 32 位整数。

回答by Adrian McCarthy

unsigned int flags = -1;  // all bits are true

"Is this a good[,] portable way to accomplish this?"

unsigned int flags = -1;  // all bits are true

“这是一个很好的[,]便携方式来完成这个吗?”

Portable? Yes.

便携的? 是的

Good? Debatable, as evidenced by all the confusion shown on this thread. Being clear enough that your fellow programmers can understand the code without confusion should be one of the dimensions we measure for good code.

好的? 值得商榷,正如该线程上显示的所有混淆所证明的那样。足够清晰,让您的程序员同行可以毫无困惑地理解代码,这应该是我们衡量良好代码的维度之一。

Also, this method is prone to compiler warnings. To elide the warning without crippling your compiler, you'd need an explicit cast. For example,

此外,此方法容易出现编译器警告。要在不削弱编译器的情况下消除警告,您需要进行显式转换。例如,

unsigned int flags = static_cast<unsigned int>(-1);

The explicit cast requires that you pay attention to the target type. If you're paying attention to the target type, then you'll naturally avoid the pitfalls of the other approaches.

显式转换要求您注意目标类型。如果您关注目标类型,那么您自然会避免其他方法的陷阱。

My advice would be to pay attention to the target type and make sure there are no implicit conversions. For example:

我的建议是注意目标类型并确保没有隐式转换。例如:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

All of which are correct and more obviousto your fellow programmers.

所有这些都是正确的,对你的程序员同事来说更明显

And with C++11: We can use autoto make any of these even simpler:

使用 C++11:我们可以使用它们auto来使任何一个更简单:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

I consider correct and obvious better than simply correct.

我认为正确和明显比简单正确更好。

回答by R.. GitHub STOP HELPING ICE

Converting -1 into any unsigned type is guaranteed by the standardto result in all-ones. Use of ~0Uis generally bad since 0has type unsigned intand will not fill all the bits of a larger unsigned type, unless you explicitly write something like ~0ULL. On sane systems, ~0should be identical to -1, but since the standard allows ones-complement and sign/magnitude representations, strictly speaking it's not portable.

标准保证将 -1 转换为任何无符号类型以产生全 1。使用 of~0U通常不好,因为0有类型unsigned int并且不会填充较大的无符号类型的所有位,除非您明确地编写类似~0ULL. 在健全的系统上,~0应该与 相同-1,但由于标准允许补码和符号/大小表示,严格来说它是不可移植的。

Of course it's always okay to write out 0xffffffffif you know you need exactly 32 bits, but -1 has the advantage that it will work in any context even when you do not know the size of the type, such as macros that work on multiple types, or if the size of the type varies by implementation. If you do know the type, another safe way to get all-ones is the limit macros UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

当然,0xffffffff如果您知道正好需要 32 位,那么写出来总是可以的,但是 -1 的优点是即使您不知道类型的大小,它也可以在任何上下文中工作,例如适用于多种类型的宏,或者如果类型的大小因实现而异。如果你知道的类型,另一种安全的方式来获得所有的人已是极限宏UINT_MAXULONG_MAXULLONG_MAX,等。

Personally I always use -1. It always works and you don't have to think about it.

我个人总是使用-1。它总是有效,您不必考虑它。

回答by Michael Norrish

As long as you have #include <limits.h>as one of your includes, you should just use

只要你有#include <limits.h>你的包含之一,你就应该使用

unsigned int flags = UINT_MAX;

If you want a long's worth of bits, you could use

如果你想要很长的价值,你可以使用

unsigned long flags = ULONG_MAX;

These values are guaranteed to have all the value bits of the result set to 1, regardless of how signed integers are implemented.

无论有符号整数是如何实现的,这些值都保证将结果的所有值位设置为 1。

回答by Diamond Python

Yes. As mentioned in other answers, -1is the most portable; however, it is not very semantic and triggers compiler warnings.

是的。正如其他答案中提到的,-1是最便携的;然而,它不是很语义化并触发编译器警告。

To solve these issues, try this simple helper:

要解决这些问题,请尝试使用这个简单的帮助程序:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Usage:

用法:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;

回答by myron-semack

I would not do the -1 thing. It's rather non-intuitive (to me at least). Assigning signed data to an unsigned variable just seems to be a violation of the natural order of things.

我不会做 -1 的事情。这相当不直观(至少对我而言)。将有符号数据分配给无符号变量似乎违反了事物的自然顺序。

In your situation, I always use 0xFFFF. (Use the right number of Fs for the variable size of course.)

在你的情况下,我总是使用0xFFFF. (当然,对于可变大小,请使用正确数量的 F。)

[BTW, I very rarely see the -1 trick done in real-world code.]

[顺便说一句,我很少在现实世界的代码中看到 -1 技巧。]

Additionally, if you really care about the individual bits in a vairable, it would be good idea to start using the fixed-width uint8_t, uint16_t, uint32_ttypes.

此外,如果您真的关心变量中的各个位,最好开始使用固定宽度的uint8_t, uint16_t,uint32_t类型。