在 C 和 C++ 中将 char 转换为 int

Posted

技术标签:

【中文标题】在 C 和 C++ 中将 char 转换为 int【英文标题】:Convert char to int in C and C++ 【发布时间】:2011-06-29 03:03:12 【问题描述】:

如何在 C 和 C++ 中将 char 转换为 int

【问题讨论】:

@Matt:更具体一点是个好主意。询问概括只会邀请那些不适用甚至对您的任务正确的概括性答案。请记住,当你不得不问的时候,你可能没有足够的知识来正确概括。 @Alf P. Steinbach:最初的问题是关于哪种语言含糊不清。使用关键字cc++,我认为两种语言的答案都是合理的。 根据我在其他技术论坛上的丰富经验,我的直觉是 OP really 的意思是“我如何获取数字的文本表示(以 10 为底)并转换对应的号码?”一般来说,C 和 C++ 新手通常对这些语言中的文本如何工作以及 char 的真正含义有难以置信模糊的想法。 @KarlKnechtel:如果这是真的(我给它大约 50/50,因为许多早期教程也鼓励从字符中获取 ASCII 值,即使 ASCII 没有覆盖全部范围),OP需要澄清 - 但这是***.com/questions/439573/…的欺骗。 OP 花了三个小时来澄清这个问题,但没有这样做。事实上,没有办法知道实际问的是什么。投票结束。 【参考方案1】:

取决于你想做什么:

要将值作为ASCII码读取,可以编写

char a = 'a';
int ia = (int)a; 
/* note that the int cast is not necessary -- int ia = a would suffice */

要转换字符'0' -> 0'1' -> 1等,可以写

char a = '4';
int ia = a - '0';
/* check here if ia is bounded by 0 and 9 */

解释a - '0'等价于((int)a) - ((int)'0'),表示字符的ascii值相减。由于0 在ascii 表中直接出现在1 之前(依此类推直到9),因此两者之间的差值就是字符a 所代表的数字。

【讨论】:

@KshitijBanerjee 这不是一个好主意,原因有两个:它为您在“0”之前的 ascii 字符提供了一个负数(例如 & -> -10),并且它为您提供了大于10(如x -> 26) int ia = a - '0' - 这就是你所需要的 @kevin001 如果要将 char 转换为 int 并且字符 '1' 提供的 ascii 数字不是 1,则需要删除偏移量 '0' 以重新对齐以计数0-9。连续数字 1-9 在 ascii 整数中相邻。 不需要/不需要演员表 @foo-bah 但是我不明白为什么我们必须用字符'0'减去它,如果我们只将该字符类型转换为整数并将其存储为整数,为什么它会抛出错误。? 【参考方案2】:

嗯,在 ASCII 码中,数字(数字)从 48 开始。您需要做的就是:

int x = (int)character - 48;

或者,由于字符'0'的ASCII码是48,你可以这样写:

int x = character - '0';  // The (int) cast is not necessary.

【讨论】:

【参考方案3】:

C 和 C++ 总是将类型提升到至少 int。此外,字符文字在 C 中属于 int 类型,在 C++ 中属于 char 类型。

您可以简单地通过分配给int 来转换char 类型。

char c = 'a'; // narrowing on C
int a = c;

【讨论】:

你也可以使用被严重低估的 unary operator+() 来达到这个目的。 -1 对于问题的唯一有意义的解释,答案是不正确的。这(代码int a = c;)将保留任何负值,这是C 标准库函数无法处理的。 C 标准库函数为将 char 值处理为 int 的含义设定了标准。 @Matt:我不赞成。如果可以的话,我会加强它!您和其他人假设的问题解释没有意义,因为它太微不足道了,并且因为对于 OP 的特定类型组合,存在一个不那么微不足道的非常重要的实际问题。你给出的建议对新手来说直接危险。对于他们使用 C 标准库字符分类函数的程序,它很可能会导致 Undefined Behavior。重新参考。对于@Sayam 的回答,他已经删除了那个回答。 -1 表示不正确:如果传递 1252 高位字符,isupper() 将产生未定义的结果。 你所说的“总是推广”是什么意思?在隐式转换、某些类型的参数传递(例如,传递给 varargs 函数)以及运算符必须使其操作数兼容类型时,值会被提升。但是肯定有一些时候一个值不会被提升(比如如果我将一个 char 传递给一个期望一个 char 的函数),否则我们不会有任何小于 int 的类型。【参考方案4】:

char 只是一个 1 字节的整数。 char 类型没有什么神奇之处!就像您可以将 short 分配给 int,或将 int 分配给 long 一样,您也可以将 char 分配给 int。

是的,原始数据类型的名称恰好是“char”,暗示它应该只包含字符。但实际上,“char”只是一个糟糕的名称选择,让所有试图学习该语言的人感到困惑。一个更好的名称是 int8_t,如果您的编译器遵循最新的 C 标准,您可以使用该名称。

当然,您在处理字符串时应该使用 char 类型,因为经典 ASCII 表的索引适合 1 个字节。您也可以使用常规整数进行字符串处理,尽管在现实世界中没有实际理由为什么您会想要这样做。例如,以下代码将完美运行:

  int str[] = 'h', 'e', 'l', 'l', 'o', '\0' ;
  
  for(i=0; i<6; i++)
  
    printf("%c", str[i]);
  

您必须意识到字符和字符串只是数字,就像计算机中的其他所有内容一样。当你在源代码中写'a'时,它被预处理成数字97,这是一个整数常量。

所以如果你写一个像这样的表达式

char ch = '5';
ch = ch - '0';

这实际上等价于

char ch = (int)53;
ch = ch - (int)48;

然后是通过C语言整数提升

ch = (int)ch - (int)48;

然后截断为字符以适应结果类型

ch = (char)( (int)ch - (int)48 );

字里行间有很多类似这样的微妙事情,其中​​ char 被隐式​​视为 int。

【讨论】:

由于该问题未使用ascii 标记,因此您不应假设任何特定编码。将char 设置为等于int8_t 是错误的,因为它同样可能是uint8_tuint24_t @RolandIllig 不,char 始终为 1 个字节,如果给定系统上存在 int8_t/uint8_t 类型(很可能),它们将能够适应char 的结果,因为它将是 8 位。在诸如各种过时的 DSP 等高度奇特的系统上,char 将是 16 位,而uint8_t 将不存在。为与过时的 DSP 兼容而编写代码是无稽之谈,为与补码或符号和幅度系统兼容而编写代码也是如此。非常浪费时间,因为这样的系统在现实世界中几乎不存在。【参考方案5】:

(这个答案解决了 C++ 方面的问题,但 C 中也存在符号扩展问题。)

处理所有三种char 类型(signedunsignedchar)比最初看起来要复杂得多。 0 到 SCHAR_MAX(对于 8 位 char 为 127)范围内的值很简单:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
int n = c;

但是,当somevalue 超出该范围时,只有通过unsigned char 才能为所有三种类型的“相同”char 值提供一致的结果:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
// Might not be true: int(c) == int(sc) and int(c) == int(uc).
int nc = (unsigned char)c;
int nsc = (unsigned char)sc;
int nuc = (unsigned char)uc;
// Always true: nc == nsc and nc == nuc.

这在使用 ctype.h 中的函数时很重要,例如 isuppertoupper,因为符号扩展:

char c = negative_char;  // Assuming CHAR_MIN < 0.
int n = c;
bool b = isupper(n);  // Undefined behavior.

注意通过 int 的转换是隐式的;这有相同的UB:

char c = negative_char;
bool b = isupper(c);

要解决这个问题,请通过unsigned char,这很容易通过将 ctype.h 函数包装到safe_ctype 来完成:

template<int (&F)(int)>
int safe_ctype(unsigned char c)  return F(c); 

//...
char c = CHAR_MIN;
bool b = safe_ctype<isupper>(c);  // No UB.

std::string s = "value that may contain negative chars; e.g. user input";
std::transform(s.begin(), s.end(), s.begin(), &safe_ctype<toupper>);
// Must wrap toupper to eliminate UB in this case, you can't cast
// to unsigned char because the function is called inside transform.

这是可行的,因为任何采用三种 char 类型中的任何一种的函数也可以采用其他两种 char 类型。它导致两个函数可以处理任何类型:

int ord(char c)  return (unsigned char)c; 
char chr(int n) 
  assert(0 <= n);  // Or other error-/sanity-checking.
  assert(n <= UCHAR_MAX);
  return (unsigned char)n;


// Ord and chr are named to match similar functions in other languages
// and libraries.

ord(c) 总是给你一个非负的值——即使传递一个负的char 或负的signed char——并且chr 取任何值ord 产生并返回完全相同的char

在实践中,我可能只是通过unsigned char 进行转换而不是使用这些,但它们确实简洁地包装了转换,提供了一个方便的位置来为int-to-char 添加错误检查,并且会是当您需要近距离使用它们多次时,它们会更短更清晰。

【讨论】:

【参考方案6】:

使用static_cast&lt;int&gt;:

int num = static_cast<int>(letter); // if letter='a', num=97

编辑:您可能应该尽量避免使用 (int)

int num = (int) 字母;

查看Why use static_cast<int>(x) instead of (int)x? 了解更多信息。

【讨论】:

【参考方案7】:

我绝对有null 的 C 技能,但是对于一个简单的解析:

char* something = "123456";

int number = parseInt(something);

...这对我有用:

int parseInt(char* chars)

    int sum = 0;
    int len = strlen(chars);
    for (int x = 0; x < len; x++)
    
        int n = chars[len - (x + 1)] - '0';
        sum = sum + powInt(n, x);
    
    return sum;


int powInt(int x, int y)

    for (int i = 0; i < y; i++)
    
        x *= 10;
    
    return x;

【讨论】:

此代码快速调用未定义的行为,因此不适合复制和粘贴。 (整数溢出)【参考方案8】:

这有点取决于您所说的“转换”是什么意思。

如果您有一系列表示整数的字符,例如“123456”,那么在 C 中有两种典型的方法可以做到这一点:使用特殊用途的转换,例如 atoi() 或 strtol(),或者通用-目的sscanf()。 C++(实际上是一种伪装成升级的不同语言)添加了第三个字符串流。

如果您的意思是希望将 int 变量之一中的确切位模式视为 char,那就更容易了。在 C 中,不同的整数类型实际上更像是一种心态,而不是实际的单独“类型”。只需在要求chars 的地方开始使用它,您应该就可以了。您可能需要显式转换以使编译器偶尔停止抱怨,但应该做的就是删除超过 256 的任何额外位。

【讨论】:

【参考方案9】:

大概您希望这种转换用于使用 C 标准库中的函数。

在这种情况下,做(C++ 语法)

typedef unsigned char UChar;

char myCppFunc( char c )

    return char( someCFunc( UChar( c ) ) );

表达式UChar( c ) 转换为unsigned char 以消除除EOF 之外的C 函数不支持的负值。

然后将该表达式的结果用作int 形式参数的实际参数。您可以在哪里自动升级到int。你也可以明确地写最后一步,比如int( UChar( c ) ),但我个人觉得这太冗长了。

干杯,

【讨论】:

【参考方案10】:

我在将"7c7c7d7d7d7d7c7c7c7d7d7d7d7c7c7c7c7c7c7d7d7c7c7c7c7d7c7d7d7d7c7c2e2e2e" 之类的字符数组转换为其实际整数值时遇到问题,该整数值可以用“7C”表示为一个十六进制值。因此,在寻求帮助之后,我创建了这个,并认为分享它会很酷。

这将 char 字符串分隔为正确的整数,并且可能对更多人有帮助,而不仅仅是我;)

unsigned int* char2int(char *a, int len)

    int i,u;
    unsigned int *val = malloc(len*sizeof(unsigned long));

    for(i=0,u=0;i<len;i++)
        if(i%2==0)
            if(a[i] <= 57)
                val[u] = (a[i]-50)<<4;
            else
                val[u] = (a[i]-55)<<4;
        
        else
            if(a[i] <= 57)
                val[u] += (a[i]-50);
            else
                val[u] += (a[i]-55);
            u++;
        
    
    return val;

希望对你有帮助!

【讨论】:

你测试过这段代码吗? 50 应该是 48,55 仅适用于大写 ASCII 字母,而您的示例包含小写字母。【参考方案11】:

对于 char 或 short to int,你只需要赋值即可。

char ch = 16;
int in = ch;

与 int64 相同。

long long lo = ch;

所有值都是 16。

【讨论】:

【参考方案12】:

我推荐使用以下功能:

/* chartoint: convert char simbols to unsigned int*/
int chartoint(char s[])


    int i, n;
    n = 0;
    for (i = 0; isdigit(s[i]); ++i)
        n = 10 * n + (s[i] - '0');
    
    return n; 

函数的结果可以通过以下方式检查:

printf("char 00: %d \r\n", chartoint("00"));
printf("char 01: %d \r\n", chartoint("01"));
printf("char 255: %d \r\n", chartoint("255"));

【讨论】:

【参考方案13】:
int charToint(char a)
char *p = &a;
int k = atoi(p);
return k;

您可以使用此 atoi 方法将 char 转换为 int。更多信息可以参考这个http://www.cplusplus.com/reference/cstdlib/atoi/,http://www.cplusplus.com/reference/string/stoi/。

【讨论】:

这是未定义的行为。获取 char 变量的地址会给你一个 char* 但不是 C 字符串,这是 atoi 所期望的。

以上是关于在 C 和 C++ 中将 char 转换为 int的主要内容,如果未能解决你的问题,请参考以下文章

无法在赋值c ++中将char *转换为int * [关闭]

c++ 不使用 C 标准库将字符串和 int 转换为 char*

在C中将char从大端转换为小端

如何在C中将char转换为整数? [复制]

在 C / C++ 中将 int* 转换为 int(*)[n]

如何在 C++ CLR 中将数组<System::Byte> 转换为 char*?