%% # 纲要 > 主干纲要、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