在C90未定义的行为定义中,“有符号或无符号类型”是什么意思?

问题描述 投票:2回答:3

在ANSI C90标准中,第6.3节有关于表达式的说法:

对象的存储值只能由具有以下类型之一的左值访问:[...]一种类型,它是有符号或无符号类型,对应于声明的对象类型的限定版本

附件G.2中存在未定义行为的这种情况:

以下情况中的行为是未定义的:[...]对象的存储值由左值访问,左值不具有以下类型之一:对象的声明类型,声明的类型的限定版本object,对应于声明的对象类型的signed或unsigned类型,对应于声明的对象类型的限定版本的signed或unsigned类型,(递归地)包括上述类型之一的聚合或联合类型其成员或字符类型(6.3)。

我发现强调部分的措辞含糊不清,并且正在努力解释它。

  1. 是否表示“签名类型对应于原始类型(如果已签名),或者对应于原始类型的无符号类型(如果它是未签名的”);或“与原始类型对应的类型(无论是签名还是未签名无关紧要)”?那就是: signed int a = -10; unsigned int b = *((unsigned int *) a); ...不确定?
  2. 如果签名/无符号无关紧要,鉴于标准区分了charsigned charunsigned char这三种类型,是否可以通过charsigned char *访问unsigned char *
c undefined-behavior c89
3个回答
4
投票

它说,将值转换为不同的签名并不是未定义的行为。如果对象声明为signed int,则可以使用unsigned int左值访问它,反之亦然。

当签名是“声明的对象类型”时,已经涵盖了签名相同的情况,尽管这种情况也可以被认为是这样。

char的情况下,signed charunsigned char都是“对应于该类型的有符号或无符号类型”。

总而言之,它只是说左值的符号性不会影响访问是否定义明确。


2
投票

请注意,附件G是资料性的,引用的相关部分是规范性C90 6.3。

这是指后来在C99中引入的“严格混叠规则”的前身。在C90中,如何处理没有类型的对象,例如malloc返回的数据,这是不明确的。

  1. 这意味着如果对象的类型是signed intunsigned int,您可以使用signed int*unsigned int*进行左值访问。允许这两种指针类型别名。例如,如果你有这样的函数: void func (signed int* a, unsigned int* b) 然后编译器不能假设ab指向不同的对象。 (请注意,奇异异常的系统理论上可以为带符号类型提供填充位和陷阱表示,因此在理论上,由于其他原因,通过unsigned int访问signed int*可能是UB。)
  2. 与其他整数类型相比,字符类型确实是一种特殊情况。但这里没关系,因为规则也有一个特殊情况:“或字符类型”。 charunsigned charsigned char都是角色类型。这意味着使用这3种类型中的任何一种对所有对L值的指针都是明确定义的。 左值类型甚至不需要是字符类型!例如,你可以通过int左右访问signed char*,它是明确定义的,但不是相反。

1
投票

当编写C89时,无符号类型是语言的一个新的补充,许多代码在int(曾经存在)的地方使用unsigned会更有意义。该标准的作者希望确保使用较新的unsigned类型的函数能够与那些使用int编写的函数交换数据,因为unsigned尚不存在。

关于像unsigned*这样的类型是否具有“对应的带符号类型”int*,或者unsigned**是否具有“相应的无符号类型”int**等,标准有点模糊。鉴于允许在无符号类型之前的代码之间进行交互的目的与使用它们,使用int*序列的unsigned*序列编写的函数将与int**的序列相反,这将与委员会的章程相悖。坚持所述目的并不要求unsigned*可以普遍用于访问unsigned *foo[10]; actOnIntPtrs((int**)foo, 10); 类型的对象,但是要求编译器给出如下构造:

unsigned*

认识到被调用的函数可能会影响存储在foo中的qazxswpoi类型的对象。

© www.soinside.com 2019 - 2024. All rights reserved.