关于C语言中字符到int的扩展符号转换

关于C语言中字符到int的扩展符号转换,c,types,integer,char,type-conversion,C,Types,Integer,Char,Type Conversion,我正在读Stephen G.Kochan写的关于C编程的书。它指出: 如果使用的字符值不是标准字符的一部分,则在转换为整数时,其符号可能会扩展 然后它说 C语言允许字符变量声明为无符号,这避免了这个潜在的问题 有人能解释一下在从char到int的转换过程中扩展符号时会出现什么问题吗? 为什么这很重要? 一个被转换成字符的负整数怎么了 谢谢在C中,纯字符可以是有符号的,也可以是无符号的,选择权留给实现 从C99,6.2.5,7: char、signed char和unsigned char这三种类

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

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

然后它说

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

有人能解释一下在从char到int的转换过程中扩展符号时会出现什么问题吗? 为什么这很重要? 一个被转换成字符的负整数怎么了

谢谢

在C中,纯字符可以是有符号的,也可以是无符号的,选择权留给实现

从C99,6.2.5,7:

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

因此,当一个字符被分配给integer时,无论字符的符号位是否被设置,都会产生歧义,因为它会影响被分配普通字符的integer的结果值

我相信,书中引用的文本提到了这一点,使用unsigned char显式地避免了这个问题。

在C中,纯字符可以是有符号的,也可以是无符号的,选择权留给实现

从C99,6.2.5,7:

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

因此,当一个字符被分配给integer时,无论字符的符号位是否被设置,都会产生歧义,因为它会影响被分配普通字符的integer的结果值


我相信,书中引用的文本提到了这一点,并且使用unsigned char明确地避免了这个问题。

假设您从isupper中获取了一个外观无辜的函数

它的定义是int-isupperint 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:它只返回给定索引处的值。除大写ASCII码为1外,数组在任何地方都用0初始化。这样一个简单而优雅的实现

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

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

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

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

*正如基思·汤普森(Keith Thompson)在评论中所说,当然不可能避免使用char。从strlen到,每个人都使用char。但是您应该注意到int的转换,特别是当char可能包含负数时。函数和数组索引是两个容易产生代价高昂的mista的地方
kes.

假设您从isupper获取了一个外观无辜的函数

它的定义是int-isupperint 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:它只返回给定索引处的值。除大写ASCII码为1外,数组在任何地方都用0初始化。这样一个简单而优雅的实现

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

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

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

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


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

所以你看,char是邪恶的,除非你真正了解如何正确使用它,否则你永远不应该使用它。-直到最后一句话我都和你在一起。如果您的程序包含字符串文字或使用任何采用char*参数的标准库函数,则使用类型char是绝对不可避免的。如果要求纯字符不带符号,有些事情会更简单、更干净,但是中的is*函数是一种相当罕见的情况,在这种情况下它会产生实际的影响。是的,我同意-标准库和许多其他库都使用字符。你真的无法避免它们。当然,我只是在夸张——它们和int一样危险,也可能溢出并导致崩溃。谁说编程很容易?夸张在印刷品中并不总是被接受。你可以考虑编辑你的最后一句话,让它更清楚,这不是完全严肃的。是的,解释这个笑话有点破坏了它。所以你看,char是邪恶的,你永远不应该使用它,除非你真正理解如何正确使用它。-直到最后一句话我都和你在一起。如果您的程序包含字符串文字或使用任何采用char*参数的标准库函数,则使用类型char是绝对不可避免的。如果要求纯字符不带符号,有些事情会更简单、更干净,但是中的is*函数是一种相当罕见的情况,在这种情况下它会产生实际的影响。是的,我同意-标准库和许多其他库都使用字符。你真的无法避免它们。当然,我只是在夸张——它们和int一样危险,也可能溢出并导致崩溃。谁说编程很容易?夸张在印刷品中并不总是被接受。你可以考虑编辑你的最后一句话,让它更清楚,这不是完全严肃的。是的,解释这个笑话有点搞糟了。