【问题标题】:About conversion of char to int in C with extending sign关于在 C 中使用扩展符号将 char 转换为 int
【发布时间】:2012-10-30 08:37:59
【问题描述】:

我正在阅读 Stephen G. Kochan 撰写的关于 C 编程的书 Programming in C。它指出:

“如果使用的字符值不是标准字符的一部分,则在转换为整数时可能会扩展其符号”

然后它说

“C语言允许将字符变量声明为无符号,这样就避免了这个潜在的问题”

有人可以解释在从 char 转换为 int 期间扩展符号时可能会出现什么问题吗? 为什么这很重要? 从字符转换成负整数有什么问题?

谢谢

【问题讨论】:

    标签: c types integer char type-conversion


    【解决方案1】:

    假设你从 isupper() 中获取了一个看起来很无辜的函数。

    它被定义为int isupper(int c);。所以它需要一个 int 并返回一个 int。

    现在,假设你不是一个非常细心的程序员,你只是将你的 char 传递给这个函数。你自己想:“会出什么问题?这是我所知道的最简单的函数!”。

    但你错了。在某个地方,有人会让她的 MP3 播放器因为这个可怕的错误而陷入无休止的崩溃循环。

    这就是原因。 C 中最烦人的类型是 char。它可以是有符号的,也可以是无符号的,你可以以一种或另一种方式强制编译器(但随后你会打开另一个蠕虫罐),最糟糕的是,标准 C 库到处都使用这种类型!

    所以,您使用 char,但您不知道它实际上已在您的环境中签名。你把它当作世界是一个 ASCII 世界来使用。

    但世界并非如此。那个快乐的 MP3 拥有者现在正在听一首著名的德国歌曲,其名称中包含字母 ä(“扩展 ASCII 码 132”)。

    你将这个字符传递给isupper(),编译器会做以下可怕的事情: “啊,它是一个字符,但是函数需要一个整数。我知道!我不会警告程序员,因为那太简单了。我只是将字符转换为整数并传递它。我该怎么做?让我们检查一下 C 标准……嗯……很简单,只需取值并对其进行符号扩展(因为 char 是有符号的,你不知道吗?)。现在,这个字符的值是 -124,所以我只需将其转换为值为 -124 的 int。这很简单,我看不出有什么大惊小怪的。我为什么还要警告程序员?!”

    现在isupper() 使用 -124 而不是 132 调用。

    但这有什么问题呢?什么都没有,除了编译器附带的 C 库使用一个简单的 128 字节数组实现 isupper():它只是返回给定索引处的值。数组初始化为 0,除了大写的 ASCII 代码,它是 1。这样一个简单而优雅的实现......

    但是等等,如果你将一个负值传递给这个函数会发生什么?好吧,那是不允许的:

    c 参数是一个 int,应用程序应将其值 确保是可表示为无符号字符或等于的字符 宏 EOF 的值。如果参数有任何其他值,则 行为未定义。

    所以,未定义的行为。在这种情况下,它会尝试访问不属于该进程的内存,然后 BAM!程序崩溃了。

    所以你看,char 是邪恶的,你不应该使用它,除非你真的了解如何正确使用它。

    (*) 正如 Keith Thompson 在评论中所说,当然不可能避免使用char。从strlen()curl_easy_escape(),大家都用char。但是您应该注意到int 的转换,尤其是当char 可能包含负数时。 函数和数组索引是容易犯代价高昂错误的两个地方。

    【讨论】:

    • “所以你看,char 是邪恶的,你永远不应该使用它,除非你真的了解如何正确使用它。” -- 直到最后我都和你在一起句子。如果您的程序包含字符串文字或使用任何采用 char* 参数的标准库函数,则使用类型 char 绝对是不可避免的。如果要求对普通的 char 进行无符号处理,有些事情会更简单、更清晰,但 <ctype.h> 中的 is*() 函数是相当罕见的情况,它会产生实际的影响。
    • 是的,我同意 - 标准库(和许多其他库)使用字符。你无法真正避免它们。当然,我只是在夸大其词-它们与int 一样危险,它也可能溢出并导致崩溃。谁说编程很容易?
    • 夸张并不总是在印刷品中得到很好的体现。你可能会考虑编辑你的最后一句话,让它更清楚地表明它并不完全严重。 (是的,解释这个笑话有点破坏它。)
    【解决方案2】:

    在 C 中,plain char 可以是有符号或无符号的,选择权留给实现。

    来自C99、6.2.5、7

    char、signed char、unsigned char这三种类型统称为 称为字符类型。实现应将 char 定义为 具有与任一有符号相同的范围、表示和行为 字符或无符号字符。

    所以当一个字符被分配给整数时,char 的符号位是否被设置会产生歧义,因为它会影响 plain char 被分配给的整数的结果值。

    我相信,书中引用的文字指的是这一点,并且使用unsigned char 明确避免了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-07
      • 2013-08-10
      • 2018-02-10
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多