%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# 相同位宽下的有符号数与无符号数的转换
给定**二进制位宽 $w$**,共有 **$2^w$ 种位模式**:
- 对于**无符号整数类型**,直接使用其 **==二进制表示==**,**无符号整数范围为 $[0, 2^w-1]$**;
- 对于**有符号整数类型**,使用 **==补码表示==**,**负数范围比正数范围多 1 个**
- **一半位模式**用于表示**负数**: $[-2^{w-1}, 0)$
- **一半位模式**表示**非负整数**:$[0, 2^{w-1}-1]$
> [!important] **相同==位宽/字长==下,有符号数与无符号数之间的类型转换==不改变位模式==,只改变==解释位模式的方式==**。
<br>
## (1)有符号数转无符号数
位宽 $w$ 下的**有符号数到无符号数**的转换:
- 对于有符号数中的正数,转为无符号类型后值不变。
- 对于有符号数中的**负数**,转为无符号类型后,**真值**变为 **==负数绝对值的补数==**。
给定**有符号负数 $-b$**,其**补码表示的位模式**在 ==**相同位宽 $w$ 的无符号数类型==** 下将被解释为**无符号数 $b_{补数}=2^w-b$**
![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-CA9117375CF13B9D88597D5B1F2801DC.png|597]]
![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-13B4744B4AA63289BF2EE02844FCE028.png|269]]
转换示意图(下例位宽为 4):
![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-2051D29B2D2B55FA92D633D995D95ACD.png|429]]
> [!example]
>
> **16 位补码表示**下,**有符号数 $-12345$** 转为**无符号数**的结果为 $53191$。 (求解过程: $2^{16}-12345=53191$)
>
> 其他示例:
> ![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-BA4A9E3A9A6266849C428D78E9FEDEB6.png|450]]
>
>
<br>
## (2)无符号数转有符号数
**位宽 $w$** 下的**无符号数到有符号数**的转换:
- 若无符号数值 $u$ **==大于==有符号数==最大值 $UMax_w$ ==** ,则转换为有符号数后的**真值为 $-u_{补数}$** ,其中 **$u_{补数} =2^w-u$**
- 若无符号数值 **$u$ 小于有符号数最大值 $UMax_w$**,则转换后真值不变。
![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-108FE9F85BA70B3483D0CAD8BB2DE8F3.png|318]]
<br><br><br>
# 有符号数与无符号数混用时的常见错误
## "有符号类型"提升为"无符号类型"的易错点
![[02-开发笔记/01-cpp/类型相关/cpp-类型转换#有符号数到无符号数的整型提升|类型转换]]
![[_attachment/02-开发笔记/03-计算机基础/数据的编码表示/有符号数与无符号数的转换.assets/IMG-有符号数与无符号数的转换-A5087D836B62FA3A2D102E7C7BF1A185.png|538]]
## 使用无符号整型时的常见错误
##### 场景一
**`unsigned int` 类型的值 $a$ 如果为 0**,对其进行减一(自减或直接算术减 1),将 **==溢出得到该类型的最大值== $4294967295$**。
因此,**如果用一个 `int` 类型的 $b$ 与其做比较,则 $b\le a$ 始终成立**。
```cpp title:exam1.cpp
/* WARNING: This is buggy code */
// 如果size为0, 则`size-1`溢出为`unsigned int`的最大值4294967295.
// 因此i<=size-1始终成立, 将导致数组越界, 访问不存在的内存, 报内存错误!
int Sum (int a[], unsigned size) {
int result = 0;
for (int i = 0; i <= size - 1; ++i) { // 正确做法是改为`i < size`
result += a[i];
}
return result;
}
```
下例中,`s.size() - w` 结果类型为无符号整型,因此可能出现溢出。
正确做法是,将判断条件改为 `i + w <= s.size()` 即可,不会出现溢出;
```cpp
/* WARNING: This is buggy code */
vector<string> findRepeatedDnaSequences(string s) {
const int w = 10;
unordered_map<string, int> s2k;
vector<string> ans;
int length = s.size();
// s.size()是无符号整型, 而w是整型, 因此`s.size() - w`的结果是无符号类型
// 当s.size()小于w时, 将溢出得到一个大数, 此时i ≤ s.size() - w始终成立, 导致数组越界.
//
// 正确做法: 将 `i <= s.size() - w` 改为 `i + w <= s.size()`
for (int i = 0; i <= s.size() - w; ++i) {
const string sub = s.substr(i, w);
++s2k[sub];
if (s2k[sub] == 2) {
ans.emplace_back(sub);
}
}
return ans;
}
```
##### 场景二
**一个较小的无符号整数减去较大的无符号整数,将发生==下溢==,结果仍然是无符号整型,始终==非负==**。
```cpp title:exam2.cpp
/* Determin whether string is longer than string t */
/* WARNING: This function is buggy */
int strlonger(char *s, char *t) {
return strlen(s) - strlen(t) > 0;
// `strlen()`返回size_t类型, 该类型在`<cstring>`中是定义为`unsigned int`
// 因此当`strlen(s) < strlen(t)`时, 二者相减的结果仍然是大于0的(下溢).
// 正确做法是改为 `return strlen(s) > strlen(t);`
}
```
<br><br>
# 参考资料
# Footnotes