C++核心准则ES.106:不要试图通过使用无符号类型避免负值

2020-06-24 10:41:04 浏览数 (2)

ES.106: Don't try to avoid negative values by using unsigned

ES.106:不要试图通过使用无符号类型避免负值

Reason(原因)

Choosing unsigned implies many changes to the usual behavior of integers, including modulo arithmetic, can suppress warnings related to overflow, and opens the door for errors related to signed/unsigned mixes. Using unsigned doesn't actually eliminate the possibility of negative values.

选择无符号数意味着修改整数的很多无用行为(如含按模运算),这会抑制溢出关联的警告信息,为有符号/无符号数混合计算相关的错误打开了大门。使用无符号数不会真的消除负值的可能性。

Example(示例)

代码语言:javascript复制
unsigned int u1 = -2;   // Valid: the value of u1 is 4294967294
int i1 = -2;
unsigned int u2 = i1;   // Valid: the value of u2 is 4294967294
int i2 = u2;            // Valid: the value of i2 is -2

These problems with such (perfectly legal) constructs are hard to spot in real code and are the source of many real-world errors. Consider:

在实际的代码中,这些(完全合法的)构造中的隐含的问题很难发现,会带来很多现实世界中的错误。考虑下面的代码:

代码语言:javascript复制
unsigned area(unsigned height, unsigned width) { return height*width; } // [see also](#Ri-expects)
// ...
int height;
cin >> height;
auto a = area(height, 2);   // if the input is -2 a becomes 4294967292

Remember that -1 when assigned to an unsigned int becomes the largest unsigned int. Also, since unsigned arithmetic is modulo arithmetic the multiplication didn't overflow, it wrapped around.

记住当-1赋给一个无符号整数时,会变成一个最大的无符号整数。同时,由于无符号数学运算是按模运算,乘法运算不会溢出,而是发生回绕。

Example(示例)

代码语言:javascript复制
unsigned max = 100000;    // "accidental typo", I mean to say 10'000
unsigned short x = 100;
while (x < max) x  = 100; // infinite loop

Had x been a signed short, we could have warned about the undefined behavior upon overflow.

如果x是一个有符号短整数,我们会收到一个由于溢出而导致无定义行为的警告。

Alternatives(其他选项)

  • use signed integers and check for x >= 0
  • 使用有符号整数并检查x是否大于0
  • use a positive integer type
  • 使用一个正整数类型
  • use an integer subrange type
  • 使用值域限定的整数类型
  • Assert(-1 < x)
  • 使用断言检查(-1<x)

For example(示例)

代码语言:javascript复制
struct Positive {
    int val;
    Positive(int x) :val{x} { Assert(0 < x); }
    operator int() { return val; }
};

int f(Positive arg) { return arg; }

int r1 = f(2);
int r2 = f(-2);  // throws
Note(注意)

???

Enforcement(实施建议)

See ES.100 Enforcements.

参考ES.100的实施建议。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es106-dont-try-to-avoid-negative-values-by-using-unsigned

0 人点赞