C 使用int和size\u t时的结果差异

C 使用int和size\u t时的结果差异,c,pointers,64-bit,32bit-64bit,size-t,C,Pointers,64 Bit,32bit 64bit,Size T,我在读一篇关于size\u t和ptrdiff\u t数据类型用法的文章时,遇到了以下示例: 守则: int A = -2; unsigned B = 1; int array[5] = { 1, 2, 3, 4, 5 }; int *ptr = array + 3; ptr = ptr + (A + B); //Error printf("%i\n", *ptr); 有几件事我无法理解。首先,添加一个有符号和一个无符号数字如何将输入结果转换为无符号类型?如果结果确实是0xFFFFFF的u

我在读一篇关于
size\u t
ptrdiff\u t
数据类型用法的文章时,遇到了以下示例:

守则:

int A = -2;
unsigned B = 1;
int array[5] = { 1, 2, 3, 4, 5 };
int *ptr = array + 3;
ptr = ptr + (A + B); //Error
printf("%i\n", *ptr);

有几件事我无法理解。首先,添加一个
有符号
和一个
无符号
数字如何将输入结果转换为
无符号
类型?如果结果确实是
0xFFFFFF
unsigned
类型,为什么在32位系统中,在与
ptr
相加时,如果数字实际上是
unsigned
类型且前导1不应表示符号,那么它会被解释为
ptr-1

第二,为什么64位系统的结果不同

有人能解释一下吗。有几件事我无法理解。首先,添加有符号和无符号数字如何将enter结果转换为无符号类型

这是由整数升迁和整数转换排名定义的

6.3.1.8 p1:否则,如果具有无符号整数类型的操作数的秩大于或等于 等于另一个操作数类型的秩,然后为 有符号整数类型转换为无符号的操作数类型 整数类型

在这种情况下,unsigned的秩高于int,因此int被提升为unsigned

int(-2)到unsigned的转换如下所述:

6.3.1.3 p2:否则,如果新类型为无符号,则通过反复添加或 比新类型中可以表示的最大值多减去一个 直到值在新类型的范围内

二,。如果结果确实是无符号类型的0xFFFFFFFF,为什么在32位系统中,在将其与ptr相加时,会将其解释为ptr-1,因为该数字实际上是无符号类型,且前导1不应表示符号

这是未定义的行为,不应依赖,因为C不定义指针算术溢出

6.5.6第8页:如果两个指针 操作数和结果指向同一数组对象的元素,或超过最后一个的元素 数组对象的元素,求值时不应产生溢出;否则 行为是未定义的

三,。第二,为什么64位系统的结果不同

(这假设(如图所示)int和unsigned为4字节。)

A和B的结果与1中所述相同,然后将该结果添加到指针。由于指针是8字节,并且假设加法没有溢出(如果ptr有一个大地址,它仍然可以溢出,给出与2相同的未定义行为),因此结果是一个地址


这是未定义的行为,因为指针指向数组边界之外。

在大多数64位上,
int
为32位,但在32位系统上,指针也为32位

回想一下,在基于32位算术的硬件中,加
0xFFFFFFFF
几乎等同于减1:它溢出,得到的是相同的数字减1(当你将9加到0到9之间的数字时,得到的是数字减1和进位,这是同样的现象)。在这种类型的硬件上,
-1
的编码实际上是相同的值
0xFFFFFFFF
,只是操作不同(有符号加法与无符号加法),因此在无符号情况下会产生进位

在64位上,指针是。。。64位。将32位值添加到64位需要将32位值扩展到64位<代码>无符号值是零扩展的(即缺失的位仅用零填充),而有符号值是符号扩展的(即缺失的位用符号位值填充)


在这种情况下,添加无符号值(因此不会进行符号扩展)不会溢出,从而产生与原始值截然不同的值。

表达式
a+B
的操作数需要进行常见的算术转换,参见C11(n1570)6.3.1.8 p1:

[……]

否则,对两个操作数执行整数提升[保持
int
无符号int
不变]。然后将以下规则应用于提升的操作数:

  • 如果两个操作数的类型相同,[…]
  • 否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,[…]
  • 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型
  • [……]
类型
int
unsigned int
具有相同的等级(同上,6.3.1.1 p1,第4项);加法的结果具有类型
unsigned int

在32位系统上,
int
和指针通常具有相同的大小(32位)。从以硬件为中心的角度来看(假设2是补码),减去
1
和添加
-1u
是相同的(有符号和无符号类型的添加是相同的!),因此对数组元素的访问似乎是可行的

但是,这是未定义的行为,因为
数组
不包含0x100000003rd元素

在64位上,
int
通常仍有32位,但指针有64位。因此,不存在概括,也不等同于减去1(从以硬件为中心的角度来看,在这两种情况下,行为都是未定义的)

举例来说,假设
ptr
为0xabcd0123,加上0xffffff得到

  abcd0123
+ ffffffff

 1abcd0122
 ^-- The 1 is truncated for a 32-bit calculation, but not for 64-bit.

邮政编码,而不是代码的图片。我很高兴有人对我的文章感兴趣。问题已经回答了。关于地址算法的更多细节:一般来说,关于64位错误有很多有趣的事情:我仍然在寻找更好的答案。将在公司内部赢得声誉