标题:此帖为质疑讨论帖,知识碰撞帖,指导贴,由我回答某人问题被质疑开展开的
只看楼主
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
结帖率:100%
 问题点数:0 回复次数:37 
此帖为质疑讨论帖,知识碰撞帖,指导贴,由我回答某人问题被质疑开展开的
此贴只讨论知识不要有个人情感
事件起因
由回答此帖的第二个问题开始的的讨论
https://bbs.bccn.net/redirect.php?goto=findpost&pid=2722914&ptid=500418
因不想自私的占用提问者的帖子,特新开一贴,继续讨论,知识难免会有碰撞,改变误区还是要贵在讨论
总结了一下,无符号数字在进行运算的时候虽然会出现陷阱,比如无符号没有负数的情况,如果在运算的时候出现负数那么就会出现很大的数,二如果溢出就会出现回绕现象,
在本帖中负数的情况没人讨论,对于溢出的情况到是有几个观点
第一个观点,如果无符号数字出现溢出就更换大的数据类型,可以是无符号类型
第二个观点,无符号类型可装的数据比有符号类型大,相对有符号更不易溢出
其他大部分都在讨论溢出和环绕的区别,以及为什么避免使用无符号类型?这里我要喊冤,本人一次没有说过避免使用无符号类型,而是说无符号类型存在陷阱,避免使用无符号数字
不过还是不建议在加减运算中使用无符号,出现负数就好玩了
还有几贴回答值得学习的慢慢吸收

[此贴子已经被作者于2020-3-20 23:57编辑过]

搜索更多相关主题的帖子: 溢出 负数 无符号 知识 出现 
2020-03-20 11:20
lin5161678
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:45
帖 子:1136
专家分:3729
注 册:2011-12-3
得分:0 
你说要避免使用无符号类型
理由是无符号数会回绕
并给出一个例子 (unsigned char)280 结果是 24
所以要避免

问题是 难道有符号类型没有回绕现象?
按照这个例子使用有符号类型 效果完全一样是 24
为什么无符号类型就需要避免使用 而有符号数就不需要避免使用了?

https://zh.
2020-03-20 13:09
纯蓝之刃
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:76
帖 子:554
专家分:3690
注 册:2019-7-29
得分:0 
我倒是认为应该尽量使用无符号类型。
因为对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”。
对于signed整型的溢出,C的规范定义是“undefined behavior”。
所以有符号整形会将溢出现象交给编译器处理,不同的编译器会有不同的处理结果。
同时在一般使用时,有符号类型会在往无符号类型转换时和动态分配内存时造成不可预知的错误。
https://blog.

一沙一世界,一花一天堂。无限掌中置,刹那成永恒。
2020-03-20 13:23
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
得分:0 
无符号类型有它的优点,但是无符号类型也存在陷阱,所以并不是让你完全禁止使用,而是除非在特殊情况下或不可避免,否则请避免使用无符号数字。
1 那么使用无符号数字在哪里合理呢?
   
首先,在进行位操作时,首选无符号数字
其次,在某些情况下仍然不可避免地要使用无符号数,主要是那些与数组索引有关的数字。
另请注意,如果您是为嵌入式系统(例如Arduino)或其他处理器/内存受限的环境而开发的,出于性能方面的考虑,无符号数的使用更为常见并被接受(在某些情况下是不可避免的)。
2 为什么说避免使用
    当不需要负数时,无符号整数非常适合于网络和内存很少的系统,因为无符号整数可以存储更多的正数而不会占用额外的内存。
无符号整数不会溢出。 取而代之的是,如果值超出范围,则将其除以该类型的最大数除以一,然后仅保留其余部分。也就是回绕
举个例子     数字280太大,无法容纳0到255的1字节范围。大于类型的最大数字的1是256。因此,我们将280除以256,得到1个余数24。24的余数 被储存了。
程序代码:
        #include <iostream>
     
    int main()
    {
        unsigned short x{ 65535 }; // largest 16-bit unsigned value 2*8。 16possible
        std::cout << "x was: " << x << '\n';
     
        x = 65536; // 65536 is out of our range, so we get wrap-around65536超出了我们的范围,因此我们得到了环绕
        std::cout << "x is now: " << x << '\n';0
     
        x = 65537; // 65537 is out of our range, so we get wrap-around65537超出了我们的范围,因此我们得到了环绕。    1
        std::cout << "x is now: " << x << '\n';
     
        return 0;
    }

程序代码:
    避免使用无符号
    #include <iostream>
     
    int main()
    {
    unsigned int x{ 3 };
    unsigned int y{ 5 };
     
    std::cout << x - y << '\n';
    return 0;
    }



    发生这种情况的原因是-2环绕到一个数字,该数字接近4字节整数范围的顶部。 当使用-运算符反复减小无符号整数时,通常会发生不必要的回绕。 引入循环后,您将看到一个示例。
    •  第二,混合有符号和无符号整数时,可能会导致意外行为。 在上面的示例中,即使其中一个操作数(x或y)是有符号的,另一个操作数(无符号的一个)也将导致有符号的一个被提升为无符号的整数,并且将产生相同的行为!
    • 除非在特殊情况下或不可避免,否则请避免使用无符号数字。
当然以上内容是我的学习笔记,有很多地方都不明白,如果对
无符号是陷阱还有疑问的话,请参阅http://soundsoftware.ac.uk/c-pitfall-unsigned.html

把学习时间浪费在混坛上是傻瓜行为,更何况自己的水平连一两都没到。
2020-03-20 13:43
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
得分:0 
你们对无符号数字有什么疑问

把学习时间浪费在混坛上是傻瓜行为,更何况自己的水平连一两都没到。
2020-03-20 13:44
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
得分:0 
当然以上是我的学习笔记纯属复制粘贴,也有很多自己删除的部分如果想看原文我可以给您们

把学习时间浪费在混坛上是傻瓜行为,更何况自己的水平连一两都没到。
2020-03-20 13:50
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
得分:0 
4.5 — Unsigned integers, and why to avoid them
BY ALEX ON APRIL 23RD, 2019 | LAST MODIFIED BY NASCARDRIVER ON MARCH 17TH, 2020
Unsigned integers

In the previous lesson (4.4 -- Signed integers), we covered signed integers, which are a set of types that can hold positive and negative whole numbers, including 0.

C++ also supports unsigned integers. Unsigned integers are integers that can only hold non-negative whole numbers.

Defining unsigned integers

To define an unsigned integer, we use the unsigned keyword. By convention, this is placed before the type:

1
2
3
4
unsigned short us;
unsigned int ui;
unsigned long ul;
unsigned long long ull;
Unsigned integer range

A 1-byte unsigned integer has a range of 0 to 255. Compare this to the 1-byte signed integer range of -128 to 127. Both can store 256 different values, but signed integers use half of their range for negative numbers, whereas unsigned integers can store positive numbers that are twice as large.

Here’s a table showing the range for unsigned integers:

Size/Type    Range
1 byte unsigned    0 to 255
2 byte unsigned    0 to 65,535
4 byte unsigned    0 to 4,294,967,295
8 byte unsigned    0 to 18,446,744,073,709,551,615
An n-bit unsigned variable has a range of 0 to (2n)-1.

When no negative numbers are required, unsigned integers are well-suited for networking and systems with little memory, because unsigned integers can store more positive numbers without taking up extra memory.

Remembering the terms signed and unsigned

New programmers sometimes get signed and unsigned mixed up. The following is a simple way to remember the difference: in order to differentiate negative numbers from positive ones, we use a negative sign. If a sign is not provided, we assume a number is positive. Consequently, an integer with a sign (a signed integer) can tell the difference between positive and negative. An integer without a sign (an unsigned integer) assumes all values are positive.

Unsigned integer overflow

Trick question: What happens if we try to store the number 280 (which requires 9 bits to represent) in a 1-byte unsigned integer? You might think the answer is “overflow!”. But, it’s not.

By definition, unsigned integers cannot overflow. Instead, if a value is out of range, it is divided by one greater than the largest number of the type, and only the remainder kept.


 
The number 280 is too big to fit in our 1-byte range of 0 to 255. 1 greater than the largest number of the type is 256. Therefore, we divide 280 by 256, getting 1 remainder 24. The remainder of 24 is what is stored.

Here’s another way to think about the same thing. Any number bigger than the largest number representable by the type simply “wraps around” (sometimes called “modulo wrapping”). 255 is in range of a 1-byte integer, so 255 is fine. 256, however, is outside the range, so it wraps around to the value 0. 257 wraps around to the value 1. 280 wraps around to the value 24.

Let’s take a look at this using 2-byte integers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
int main()
{
    unsigned short x{ 65535 }; // largest 16-bit unsigned value possible
    std::cout << "x was: " << x << '\n';
 
    x = 65536; // 65536 is out of our range, so we get wrap-around
    std::cout << "x is now: " << x << '\n';
 
    x = 65537; // 65537 is out of our range, so we get wrap-around
    std::cout << "x is now: " << x << '\n';
 
    return 0;
}
What do you think the result of this program will be?

x was: 65535
x is now: 0
x is now: 1
It’s possible to wrap around the other direction as well. 0 is representable in a 1-byte integer, so that’s fine. -1 is not representable, so it wraps around to the top of the range, producing the value 255. -2 wraps around to 254. And so forth.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
int main()
{
    unsigned short x{ 0 }; // smallest 2-byte unsigned value possible
    std::cout << "x was: " << x << '\n';
 
    x = -1; // -1 is out of our range, so we get wrap-around
    std::cout << "x is now: " << x << '\n';
 
    x = -2; // -2 is out of our range, so we get wrap-around
    std::cout << "x is now: " << x << '\n';
 
    return 0;
}
x was: 0
x is now: 65535
x is now: 65534
Author's note

In common language, unsigned integer wrap around is often incorrectly called “overflow” since the cause is identical to signed integer overflow.
As an aside...

Many notable bugs in video game history happened due to wrap around behavior with unsigned integers. In the arcade game Donkey Kong, it’s not possible to go past level 22 due to a bug that leaves the user with not enough bonus time to complete the level. In the PC game Civilization, Gandhi was known for being the first one to use nuclear weapons, which seems contrary to his normally passive nature. Gandhi’s aggression setting was normally set at 1, but if he chose a democratic government, he’d get a -2 modifier. This wrapped around his aggression setting to 255, making him maximally aggressive!
The controversy over unsigned numbers

Many developers (and some large development houses, such as Google) believe that developers should generally avoid unsigned integers.

This is largely because of two behaviors that can cause problems.

First, consider the subtraction of two unsigned numbers, such as 3 and 5. 3 minus 5 is -2, but -2 can’t be represented as an unsigned number.

1
2
3
4
5
6
7
8
9
10
#include <iostream>
 
int main()
{
    unsigned int x{ 3 };
    unsigned int y{ 5 };
 
    std::cout << x - y << '\n';
    return 0;
}
On the author’s machine, this seemingly innocent looking program produces the result:

1
4294967294
This occurs due to -2 wrapping around to a number close to the top of the range of a 4-byte integer. A common unwanted wrap-around happens when an unsigned integer is repeatedly decremented with the -- operator. You’ll see an example of this when loops are introduced.

Second, unexpected behavior can result when you mix signed and unsigned integers. In the above example, even if one of the operands (x or y) is signed, the other operand (the unsigned one) will cause the signed one to be promoted to an unsigned integer, and the same behavior will result!

Consider the following snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
void doSomething(unsigned int x)
{
    // Run some code x times
 
    std::cout << "x is " << x << '\n';
}
 
int main()
{
    doSomething(-1);
 
    return 0;
}
The author of doSomething() was expecting someone to call this function with only positive numbers. But the caller is passing in -1. What happens in this case?

The signed argument of -1 gets implicitly converted to an unsigned parameter. -1 isn’t in the range of an unsigned number, so it wraps around to some large number (probably 4294967295). Then your program goes ballistic. Worse, there’s no good way to guard against this condition from happening. C++ will freely convert between signed and unsigned numbers, but it won’t do any range checking to make sure you don’t overflow your type.

If you need to protect a function against negative inputs, use an assertion or exception instead. Both are covered later.

Some modern programming languages (such as Java) and frameworks (such as .NET) either don’t include unsigned types, or limit their use.

New programmers often use unsigned integers to represent non-negative data, or to take advantage of the additional range. Bjarne Stroustrup, the designer of C++, said, “Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea”.

Warning

Avoid using unsigned numbers, except in specific cases or when unavoidable.

Don’t avoid negative numbers by using unsigned types. If you need a larger range than a signed number offers, use one of the guaranteed-width integers shown in the next lesson (4.6 -- Fixed-width integers and size_t).

If you do use unsigned numbers, avoid mixing signed and unsigned numbers where possible.
So where is it reasonable to use unsigned numbers?

There are still a few cases in C++ where it’s okay (or necessary) to use unsigned numbers.

First, unsigned numbers are preferred when dealing with bit manipulation (covered in chapter O).

Second, use of unsigned numbers is still unavoidable in some cases, mainly those having to do with array indexing. We’ll talk more about this in the lessons on arrays and array indexing.

Also note that if you’re developing for an embedded system (e.g. an Arduino) or some other processor/memory limited context, use of unsigned numbers is more common and accepted (and in some cases, unavoidable) for performance reasons.

把学习时间浪费在混坛上是傻瓜行为,更何况自己的水平连一两都没到。
2020-03-20 13:52
叶纤
Rank: 8Rank: 8
等 级:禁止访问
威 望:1
帖 子:658
专家分:848
注 册:2019-11-22
得分:0 
当然以上内容我可能用翻译软件翻译的不到位,那请你们指出哪里翻译的不好,我知道不论是有符号还是无符号类型,整数都有可能益处,不过面对无符号的数字益出我更喜欢用回绕这个词,有符号的数字益处有可能是—526724835739这样的数字
所以面对整数益出网站上也有一些评论
整数溢出

如果我们尝试将值280分配给1个字节的有符号整数会怎样?此数字超出1字节有符号整数可以容纳的范围。数字280需要表示9位(加上1个符号位),但是在1字节有符号整数中,我们只有7位(加上1个符号位)可用。

当我们尝试存储超出类型范围的值时,会发生整数溢出(通常简称为溢出)。本质上,我们要存储的数字表示的位数比对象可用的位数更多。在这种情况下,数据丢失是因为对象没有足够的内存来存储所有内容。

在有符号整数的情况下,丢失哪些位的定义不明确,因此有符号整数溢出会导致未定义的行为。

警告

有符号整数溢出将导致不确定的行为。
通常,溢出会导致信息丢失,这几乎是不希望的。如果有任何怀疑的对象可能需要存储落在其范围之外的值,使用类型有一个更大的范围内!

整数除法
英文版
Integer overflow

What happens if we try to assign the value 280 to a 1-byte signed integer? This number is outside the range that a 1-byte signed integer can hold. The number 280 requires 9 bits (plus 1 sign bit) to be represented, but we only have 7 bits (plus 1 sign bit) available in a 1-byte signed integer.

Integer overflow (often called overflow for short) occurs when we try to store a value that is outside the range of the type. Essentially, the number we are trying to store requires more bits to represent than the object has available. In such a case, data is lost because the object doesn’t have enough memory to store everything.

In the case of signed integers, which bits are lost is not well defined, thus signed integer overflow leads to undefined behavior.

Warning

Signed integer overflow will result in undefined behavior.
In general, overflow results in information being lost, which is almost never desirable. If there is any suspicion that an object might need to store a value that falls outside its range, use a type with a bigger range!

把学习时间浪费在混坛上是傻瓜行为,更何况自己的水平连一两都没到。
2020-03-20 14:00
lin5161678
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:45
帖 子:1136
专家分:3729
注 册:2011-12-3
得分:0 
回复 7楼 叶纤
无符号类型我很熟悉 不需要看你的笔记

你说要避免使用无符号类型 却不能解释清楚为什么
目前只看到有一个所谓的理由是 回绕
(signed char)280 结果是 24
3U - 5U 结果是一个非常大的整数

问题是这个现象 有符号类型/无符号类型都会出现
无非是出现这个现象的数值不同
这样的理由不足以用于说明 为什么要避免使用无符号类型

https://zh.
2020-03-20 14:10
lin5161678
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:45
帖 子:1136
专家分:3729
注 册:2011-12-3
得分:0 
以下是引用叶纤在2020-3-20 14:00:07的发言:

当然以上内容我可能用翻译软件翻译的不到位,那请你们指出哪里翻译的不好,我知道不论是有符号还是无符号类型,整数都有可能益处,不过面对无符号的数字益出我更喜欢用回绕这个词,有符号的数字益处有可能是—526724835739这样的数字
所以面对整数益出网站上也有一些评论
整数溢出

如果我们尝试将值280分配给1个字节的有符号整数会怎样?此数字超出1字节有符号整数可以容纳的范围。数字280需要表示9位(加上1个符号位),但是在1字节有符号整数中,我们只有7位(加上1个符号位)可用。

当我们尝试存储超出类型范围的值时,会发生整数溢出(通常简称为溢出)。本质上,我们要存储的数字表示的位数比对象可用的位数更多。在这种情况下,数据丢失是因为对象没有足够的内存来存储所有内容。

在有符号整数的情况下,丢失哪些位的定义不明确,因此有符号整数溢出会导致未定义的行为。

警告

有符号整数溢出将导致不确定的行为。
通常,溢出会导致信息丢失,这几乎是不希望的。如果有任何怀疑的对象可能需要存储落在其范围之外的值,使用类型有一个更大的范围内!

整数除法
英文版
Integer overflow

What happens if we try to assign the value 280 to a 1-byte signed integer? This number is outside the range that a 1-byte signed integer can hold. The number 280 requires 9 bits (plus 1 sign bit) to be represented, but we only have 7 bits (plus 1 sign bit) available in a 1-byte signed integer.

Integer overflow (often called overflow for short) occurs when we try to store a value that is outside the range of the type. Essentially, the number we are trying to store requires more bits to represent than the object has available. In such a case, data is lost because the object doesn’t have enough memory to store everything.

In the case of signed integers, which bits are lost is not well defined, thus signed integer overflow leads to undefined behavior.

Warning

Signed integer overflow will result in undefined behavior.
In general, overflow results in information being lost, which is almost never desirable. If there is any suspicion that an object might need to store a value that falls outside its range, use a type with a bigger range!

这一层的内容可以这样解读
如果会出现溢出现象 应该使用更大类型
如果不使用更大类型 也应该考虑使用无符号类型 而不使用有符号类型
因为 有符号类型溢出是未定义行为 无符号类型溢出保证是回绕

这同样不是一个 避免使用无符号类型的理由


[此贴子已经被作者于2020-3-20 14:14编辑过]

收到的鲜花
  • 叶纤2020-03-20 22:02 送鲜花  4朵   附言:感谢你的质疑

https://zh.
2020-03-20 14:13



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-500456-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.092688 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved