37

如果我想将单个数字转换char为它的数值,例如,如果:

char c = '5';

我想c持有5而不是'5',它是 100% 便携的吗?

c = c - '0';

我听说所有字符集都按连续顺序存储数字,所以我假设是这样,但我想知道是否有组织的库函数来进行这种转换,以及它是如何按常规完成的。我是一个真正的初学者:)

4

10 回答 10

28

是的,这是一个安全的转换。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”的方法是正确的方法。我只是想在这里展示如何使用推荐的将数字作为字符串转换为“真实”数字的标准方法。

于 2009-04-23T13:30:24.503 回答
9

试试这个 :

char c = '5' - '0';
于 2009-04-23T13:30:13.363 回答
5

您可以使用atoi,它是标准库的一部分。

于 2009-04-23T13:29:40.153 回答
5
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 */
}

这会将单个十六进制字符(大写或小写独立)转换为整数。

于 2009-04-24T14:12:02.777 回答
3

由于您只转换一个字符,因此 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以下的角色基本相同。这将包括代表数字的字符。这意味着您提出的基本数学应该适用于您想要实现的目标。

于 2009-04-23T13:50:33.957 回答
1

是的。只要您使用标准的 ascii 字符,这就是安全的,就像您在本例中一样。

于 2009-04-23T13:28:27.923 回答
0

通常,如果不能保证您的输入在 '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我知道这是一个矫枉过正。我只是想把它作为一种可能不会立即显现出来的替代解决方案。

于 2009-04-24T15:33:23.687 回答
0

正如其他人所建议的那样,但包装在一个函数中:

int char_to_digit(char c) {
    return c - '0';
}

现在只需使用该功能。如果您决定使用不同的方法,您只需要更改实现(性能、字符集差异等),您不需要更改调用者。

此版本假定 c 包含一个表示数字的字符。您可以在调用函数之前使用 ctype.h 的 isdigit 函数进行检查。

于 2013-05-10T22:19:08.793 回答
0

由于 '0','1','2'.... 的 ASCII 代码从 48 到 57 放置,它们基本上是连续的。现在算术运算需要将 char 数据类型转换为 int 数据类型。因此您基本上要做的是:53-48,因此它存储值 5,您可以使用它进行任何整数运算。请注意,从 int 转换回 char 时编译器没有给出错误,只是执行模 256 运算以将值置于可接受的范围内

于 2014-06-21T15:46:44.120 回答
0

您可以简单地使用该atol()功能:

#include <stdio.h>
#include <stdlib.h>

int main() 
{
    const char *c = "5";
    int d = atol(c);
    printf("%d\n", d);

}
于 2017-06-03T00:24:08.167 回答