如果我想将单个数字转换char
为它的数值,例如,如果:
char c = '5';
我想c
持有5
而不是'5'
,它是 100% 便携的吗?
c = c - '0';
我听说所有字符集都按连续顺序存储数字,所以我假设是这样,但我想知道是否有组织的库函数来进行这种转换,以及它是如何按常规完成的。我是一个真正的初学者:)
是的,这是一个安全的转换。C 要求它工作。该保证在最新 ISO C 标准的第 5.2.1 节第 2 段中,最近的草案是N1570:
基本源字符集和基本执行字符集都应具有以下成员:
[...]
10 位十进制数字
0 1 2 3 4 5 6 7 8 9
[...]
在源基本字符集和执行基本字符集中,上述列表中 0 之后的每个字符的值小数位数应比前一个值大一。
ASCII 和 EBCDIC 以及从它们派生的字符集都满足这个要求,这就是 C 标准能够强加它的原因。请注意,字母在EBCDIC中是不连续的,而 C 并不要求它们是连续的。
没有库函数可以为单个 执行此操作char
,您需要先构建一个字符串:
int digit_to_int(char d)
{
char str[2];
str[0] = d;
str[1] = '\0';
return (int) strtol(str, NULL, 10);
}
一旦你有一个字符串,你也可以使用该atoi()
函数进行转换,但strtol()
更好更安全。
正如评论者指出的那样,调用一个函数来进行这种转换是非常过分的。您最初减去“0”的方法是正确的方法。我只是想在这里展示如何使用推荐的将数字作为字符串转换为“真实”数字的标准方法。
试试这个 :
char c = '5' - '0';
您可以使用atoi
,它是标准库的一部分。
int i = c - '0';
您应该知道,这不会对字符执行任何验证 - 例如,如果字符是“a”,那么您将得到 91 - 48 = 49。尤其是在处理用户或网络输入时,您可能应该执行验证以避免程序中的不良行为。只需检查范围:
if ('0' <= c && c <= '9') {
i = c - '0';
} else {
/* handle error */
}
请注意,如果您希望您的转换处理十六进制数字,您可以检查范围并执行适当的计算。
if ('0' <= c && c <= '9') {
i = c - '0';
} else if ('a' <= c && c <= 'f') {
i = 10 + c - 'a';
} else if ('A' <= c && c <= 'F') {
i = 10 + c - 'A';
} else {
/* handle error */
}
这会将单个十六进制字符(大写或小写独立)转换为整数。
由于您只转换一个字符,因此 atoi() 函数太过分了。atoi() 在转换数字的字符串表示时很有用。其他帖子已经给出了这方面的例子。如果我正确阅读了您的帖子,则您只转换了一个数字字符。因此,您只需要转换 0 到 9 范围内的字符。在只转换一个数字字符的情况下,减去“0”的建议将为您提供所需的结果。这样做的原因是因为 ASCII 值是连续的(就像你说的那样)。因此,减去 0 的 ASCII 值(ASCII 值 48 - 请参阅ASCII 表对于值)来自数字字符将给出数字的值。因此,您的 c = c - '0' 示例,其中 c = '5',实际发生的是 53(5 的 ASCII 值)- 48(0 的 ASCII 值)= 5。
当我第一次发布这个答案时,我没有考虑你关于在不同字符集之间 100% 可移植的评论。我做了一些进一步的环顾四周,看起来你的答案仍然大部分是正确的。问题是您使用的是 8 位数据类型的 char。这不适用于所有字符类型。阅读Joel Spolsky 撰写的关于 Unicode的这篇文章有关 Unicode 的更多信息。在这篇文章中,他说他使用 wchar_t 来表示字符。这对他来说效果很好,他用 29 种语言发布了他的网站。因此,您需要将 char 更改为 wchar_t。除此之外,他说127以下的角色基本相同。这将包括代表数字的字符。这意味着您提出的基本数学应该适用于您想要实现的目标。
是的。只要您使用标准的 ascii 字符,这就是安全的,就像您在本例中一样。
通常,如果不能保证您的输入在 '0'..'9' 范围内,则必须执行如下检查:
if (c >= '0' && c <= '9') {
int v = c - '0';
// safely use v
}
另一种方法是使用查找表。您可以使用更少(可能更快)的代码进行简单的范围检查和转换:
// one-time setup of an array of 256 integers;
// all slots set to -1 except for ones corresponding
// to the numeric characters
static const int CHAR_TO_NUMBER[] = {
-1, -1, -1, ...,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // '0'..'9'
-1, -1, -1, ...
};
// Now, all you need is:
int v = CHAR_TO_NUMBER[c];
if (v != -1) {
// safely use v
}
PS我知道这是一个矫枉过正。我只是想把它作为一种可能不会立即显现出来的替代解决方案。
正如其他人所建议的那样,但包装在一个函数中:
int char_to_digit(char c) {
return c - '0';
}
现在只需使用该功能。如果您决定使用不同的方法,您只需要更改实现(性能、字符集差异等),您不需要更改调用者。
此版本假定 c 包含一个表示数字的字符。您可以在调用函数之前使用 ctype.h 的 isdigit 函数进行检查。
由于 '0','1','2'.... 的 ASCII 代码从 48 到 57 放置,它们基本上是连续的。现在算术运算需要将 char 数据类型转换为 int 数据类型。因此您基本上要做的是:53-48,因此它存储值 5,您可以使用它进行任何整数运算。请注意,从 int 转换回 char 时编译器没有给出错误,只是执行模 256 运算以将值置于可接受的范围内
您可以简单地使用该atol()
功能:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const char *c = "5";
int d = atol(c);
printf("%d\n", d);
}