为什么指针算术中的整数提升在64位代码中的表现与在32位代码中不同
Why does integer promotion in pointer arithmetic behave differently in 64bit code than it does in 32bit code?
当为64位编译时,以下代码在访问ptr[1-offset]
:时因访问违规而崩溃
char* ptr = new char[4];
strcpy(ptr, "bar");
unsigned int offset = 2;
ptr+=offset;
char test0 = (ptr-offset)[2];
char test1 = ptr[2-offset];
char test2 = (ptr-offset)[1];
char test3 = ptr[1-offset];
delete (ptr-offset);
当编译为32位时,代码执行得很好。
当我用ptr[(int)(1-offset)]
替换ptr[1-offset]
时,或者当我把unsigned int offset = 2;
改成int offset = 2;
时,代码对64位也执行得很好。
显然,在64位上,1-offset
的结果被提升为无符号整数类型,因此ptr[1-offset]
不会解析为ptr[-1]
,而是解析为ptr[maxValueOfSomeUnsignedIntegerType]
。
然而,为什么这种情况只发生在64位,而1-offset
似乎被提升为32位的有符号整数类型?
这似乎不是特定于实现的——我用VC++和G++得到了相同的结果。
首先,1-offset
的结果始终是UINT_MAX
,与您的体系结构无关。仅凭这一点并不能解释差异。
如果将其强制转换为int
,则会得到一个实现定义的结果,但通常是-1
。与int offset
相同,您只需要得到普通的带符号整数运算,即可得到-1
。这样就行了。
现在来解释为什么会出现segfault:显然,在你尝试的系统上,指针上的溢出算术会包裹mod2^32。据我所知,这是UB,但它似乎适用于您的系统。所以你实际上最终得到了ptr[1]
。
另一方面,如果指针是64位宽的,它可以表示ptr + 2^32 - 1
(至少在这种情况下是明显的),因此不会发生包装,并且指针指向分配后大约4GB的某个无意义位置。
1
属于int
类型。CCD_ 21属于CCD_。
整数提升不适用(仅适用于小于int
的类型)。然后,运算符-
应用通常的算术转换。因为两个输入都具有相同的秩(int
),并且只有符号不同,所以输入被转换为类型unsigned int
。
所以1-offset
总是类型为unsigned int
,值为UINT_MAX
。这适用于32位和64位构建。
索引指针会导致越界访问,因此代码在32位和64位平台上都有未定义的行为。
对于32位,指针计算恰好是环绕的,因此您可以获得与ptr[-1]
相同的效果(假设优化器没有利用UB),而对于64位,指针运算不会溢出,通常会得到segfault。
- 将应用程序从32位移植到64位时出现问题
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- qmake:检测目标位宽(32 位或 64 位)
- 如何在 64 位 vb.net Windows 应用程序中引用 32 位 dll
- 将代码从 32 位迁移到 64 位时出现问题 Visual Studio 2010
- 将 32 位旧代码移植到 64 位时如何处理更改数据类型大小?
- 将32位和64位应用程序(具有相同代码)编译为一个EXE
- 使用MINGW-W64使用-M32选项(32位代码)编译时错误
- MSVC:在64位代码中读取特定的64位或32位寄存器(例如R10)
- 试用版代码在 Windows 上的 32 位运行速度比在 Linux 上的 64 位快 2 倍
- 移植将 32 位浮点数与使用 64 位进行比较的代码,此值表示什么
- 将 32 位端口代码移植到 64 位代码
- 将c++代码从32位机器迁移到64位机器
- 为什么指针算术中的整数提升在64位代码中的表现与在32位代码中不同
- 在 32 位 Linux 上编译代码时出现错误'gtk_window_set_keep_above'未声明
- 什么是 32 位和 64 位 c++ 代码?
- C++代码从32位到64位的转换
- 如何编写可转换代码,32位/64位
- 在Windows XP 32位上安装GSL以使用代码块
- 如何从32位代码中以64位启动Windows进程