【问题标题】:How exactly is this function an example of a char to int conversion?这个函数究竟是如何将 char 转换为 int 的示例?
【发布时间】:2019-05-24 08:59:45
【问题描述】:

Kernighan 和 Ritchie 所著的C 编程语言一书,第二版在第 43 页关于类型转换一章中陈述:

char 到 int 转换的另一个示例是函数 lower,它将单个字符映射为小写 ASCII 字符集。如果字符不是大写字母,lower 返回原样返回。

/* lower: convert c to lower case; ASCII only */
int lower(int c)
{
    if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
    else
        return c;
}

文本中没有明确提及,所以我想确保我理解正确:转换发生在您使用 char 类型的变量调用 lower 函数时,不是吗?尤其是表达式

c >= 'A'

与从int 到char 的转换无关,因为像'A' 这样的字符常量 从一开始就在内部作为int 处理,不是吗?编辑:或者这本书涵盖的 ANSI C 是不同的(例如,一个字符常量被视为char)?

【问题讨论】:

  • 不,他们所说的转换发生在 inside 函数体中。

标签: c type-conversion kernighan-and-ritchie


【解决方案1】:

字符常量的类型为int,如您所料,因此您是正确的,在此函数中没有对int 的提升。

如果将 char 类型的变量传递给此函数,则可能发生的任何提升都会发生,这很可能是文本所指的内容。

当前C17 standard中的字符常量类型均为int(第6.4.4.4p10节):

一个整数字符常量有类型 int

在C89 / ANSI C standard(语义下的第 3.1.3.4 节)中:

整数字符常量的类型为int

后者是K&R第二版所指的。

【讨论】:

  • K&R 领先于 C 标准。是否有理由相信,在他们的文本中,'a' 的类型是 int 而不是 char?
  • @EricPostpischil 在第 37 页该书说:“字符常量 是一个整数,写为单引号内的一个字符,例如 'x'”。我不确定“是整数”是否意味着“类型为int”?
  • @efie:char、short、int和long都是整数类型,整数只是一个值,所以我不认为它们对字符的引用作为一个整数是有用的。
  • 有道理,谢谢。关于您的第一条评论:本书的第二页说:“The C Programming Language 的第二版描述了 ANSI 标准定义的 C。”
【解决方案2】:

K&R C 是旧的。真的老了。 K&R C 的许多细节在最新的标准 C 中不再正确。

在标准的最新 C11 中,您发布的函数中没有与 char 的转换:

/* lower: convert c to lower case; ASCII only */
int lower(int c)
{
    if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
    else
        return c;
}

该函数接受int 参数作为int c,并且根据6.4.4.4 Character constants of the C standard,字符文字的类型为int。

因此,在 C11 下发布的整个 lower 函数完全处理 int 值。

如果有转换,可以在调用函数时完成:

char upperA = 'A`;

// this will implicitly promote the upperA char
// value to an int value
char lowerA = lower( upperA );

请注意,这是 C 和 C++ 之间的区别之一。在 C++ 中,字符文字的类型是 char,而不是 int。

【讨论】:

  • 谢谢!你知道字符常量在 ANSI C 中是否也是 int 类型的吗?或者是 char 类型的,它会添加另一种解释?
  • 自 C89 以来,这个函数没有任何改变。
【解决方案3】:

这个函数究竟是如何将char 转换为int 的示例?

/* lower: convert c to lower case; ASCII only */
int lower(int c) {
    if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
    else
        return c;
}

这不是 char 到 int 转换的示例 - 作者在技术上不正确。


本文继续讨论tolower(c) 作为lower() 的替代方案,因为即使[A -Z] 没有像EBCDIC 那样连续编码,它也能正确“工作”。

没有讨论的是,tolower() 函数和其他 (is...()) 仅针对 unsigned char 范围和 EOF 中的 int 值指定。 C11 §7.4 1. 其他值调用未定义的行为 (UB)。

正是这个要求使得这些标准 C 库函数在概念上 char 到 int 的转换只指定了(大约)char 范围内的值,结果为 @987654337 @。


现在看看发生char转换的代码。

void my_strtolower1(char *s) {
  while (*s) {
    *s = lower(*s);  // conversion `char` to `int` and `int` to `char`.
    s++;
  }
} 

void my_strtolower2(char *s) {
  while (*s) {
    *s = tolower(*s); // conversion `char` to `int` and `int` to `char`.
    s++;
  }
} 

void my_strtolower3(char *s) {
  while (*s) {
    // conversion `char` to `unsigned char` to `int` and `int` to `char`.
    *s = tolower((unsigned char) *s); 
    s++;
  }
} 

my_strtolower1() 定义明确,但在 [A-Z,a-z] 不连续的稀有机器上功能不正确。

my_strtolower2() 预期的功能,但在 *s &lt; 0(而不是 EOF)时技术上未定义的行为除外。

my_strtolower3()*s &lt; 0 时没有 UB 的预期功能。

【讨论】:

    猜你喜欢
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 2017-03-21
    • 1970-01-01
    • 2018-01-19
    • 2011-04-09
    • 2018-05-15
    相关资源
    最近更新 更多