我一直在阅读 Jens Gustedt 所著的 Modern C 书以及第 8.4 节,其中介绍了处理字符串处理和转换的 C 库函数,其中有一段代码定义了一个函数它将表示十六进制 (36) 基数的单个 char(使用其 int 值)转换为其十进制等效值。这个函数应该解释 <stdlib.h> 的 strtoul 函数的一部分是如何工作的。
这是提供的代码:
/* Supposes that lowercase characters are contiguous. */
static_assert('z'-'a' == 25,
"alphabetic characters not contiguous");
#include <ctype.h>
/* Converts an alphanumeric digit to an unsigned */
/* '0' ... '9' => 0 .. 9u */
/* 'A' ... 'Z' => 10 .. 35u */
/* 'a' ... 'z' => 10 .. 35u */
/* Other values => Greater */
unsigned hexatridecimal(int a) {
if (isdigit(a)) {
/* This is guaranteed to work: decimal digits
are consecutive, and isdigit is not
locale dependent. */
return a - '0';
} else {
/* Leaves a unchanged if it not lowercase */
a = toupper(a);
/* Returns value >= 36 if not Latin uppercase */
return (isupper(a)) ? 10 + (a - 'A') : -1;
}
}
问题是,要将字母转换为十进制值,需要使用 (a - 'A'),其中 a 表示要转换的字母。关于这个操作,作者是这样进行的:
第二个return十六进制对a和'A'之间的关系做出假设。它是什么?
描述不满足此假设的错误场景。
修复此错误:即重写代码,使其不对a和'A'之间的关系做出任何假设。
现在,我不知道我是否漏掉了一些关键信息,或者是否遗漏了其他信息,但我无法弄清楚点号 2 和 3。
对于第一点,我认为假设是 a 大于或等于 'A'。因为这是根据函数上面的注释产生正确值所需要的。问题是,通过在代码开头使用 static_assert 和在 return 行使用 三元运算符,以 isupper(a) 作为条件,我看不到它发生,因此不不知道第二点该争论什么。因此,我也陷入了第三点。
这个假设和我的假设有什么不同吗?这有什么错误,什么时候会导致错误以及如何修复它?
abcde0123456789pqrstuwxyzfghijklmno
'z' - 'a' == 25
hexatridecimal
,因为它不限制字符为数字和'ABCDEF`。因此,如果在将 base16 字符串转换为整数的函数中使用它,则会出现不稳定的错误。