C 程序在指针运算后崩溃(仅在某些计算机中)
Posted
技术标签:
【中文标题】C 程序在指针运算后崩溃(仅在某些计算机中)【英文标题】:C program crashes after pointer arithmetic (only in some computers) 【发布时间】:2018-07-27 09:31:43 【问题描述】:我有以下代码(不是我写的,简化后只显示有问题的部分):
#include <stdlib.h>
typedef struct test_struct
unsigned int foo;
char *dummy;
test_struct;
int main()
test_struct *s = (test_struct *) malloc(10 * sizeof(test_struct));
s = (test_struct *)((unsigned long)s + 16);
s->foo = 1; // crash!
程序为 10 个结构(在我的平台中为 10*24 字节)分配内存。然后,指针增加了 16 个字节,并尝试在该位置写入一个数字。
我已经在 4 台计算机上测试了这个 sn-p。其中两个在 Windows 7 x64 上运行,并且运行良好。另一个在 lubuntu x64 上运行,也可以按预期工作。另一个是 Windows 10 x64,它崩溃了。
你能帮我理解这些行有什么问题吗?我正在使用执行此操作的第三方库,但我不知道到底发生了什么。
【问题讨论】:
你知道一个结构是24字节吗?即使是这样,那你为什么认为指向内存的 16 字节指针是有效的呢?添加 24 字节的偏移量(或任何sizeof(test_struct)
可能)不会更有意义吗?
导致这个问题的真正问题是什么?你为什么要问?这样的用例是什么?
“按预期工作”这句话有点棘手。我认为这只是意味着您没有看到崩溃。仅仅因为程序“按预期工作”并不意味着它不是错误。你可以运行它,不会出错,但它仍然可能正在写入它不应该写入的内存。
@Someprogrammerdude,我知道 struct if 24 bytes 因为我在测试中打印了值。我希望指针是有效的,因为我分配了足够的空间(即使我分配了 5000 个字节它也不起作用)。我同意这没有多大意义,但我没有编写代码,我正在尝试修复它。谢谢!
问题不仅在于尺寸,还在于对齐。有些数据不能放在某些系统上的任何地址上。在这些平台上,未对齐的访问可能会导致异常。
【参考方案1】:
s = (test_struct *)((unsigned long)s + 16);
在某些平台上long
不足以存储指针,因此请改用uintptr_t
:
s = (test_struct *)((uintptr_t)s + 16);
程序为 10 个结构(在我的例子中为 10*24 字节)分配内存。然后,指针增加了 16 个字节
无论您要实现什么,请注意结构的大小也取决于平台。不仅结构内部的字段,不同平台上的填充也可能不同。
所以在计算中我们最好使用sizeof
和offsetof
而不是像16
这样的幻数。
【讨论】:
值得注意的是,使用 Visual C++ 编译器的 64 位 Windows 就是这些平台之一。 谢谢,安德烈。我说“在我的情况下”是 10*24 字节,因为我打印了 sizeof(struct) 结果来检查该结构占用了多少内存。此外,真正的库不会添加 16 字节的硬编码值,但我发现在给定的执行或给定的设置中,当它崩溃时它是 16 字节。我不明白的是,如果分配了很多内存,为什么即使不是分配部分的初始位置也不能写入数字?我不喜欢这个库的编码方式,但我必须修复它才能运行我的程序。 @ZuhaitzBeloki 您无法写入,因为您正在转换为unsingned long
,在某些平台上可能只有 32 位。您应该改用uintptr_t
。请参阅我的答案的开头;)
你是对的,@AndriyBerestovskyy。现在可以了。谢谢!【参考方案2】:
test_struct *s = (test_struct *) malloc(10 * sizeof(test_struct)); s = (test_struct *)((unsigned long)s + 16);
您的程序中存在多个错误:- 1.您应该了解内存分配完全取决于操作系统。如何以及为什么要长时间递增 16,它可能会溢出。 2.在 s 中更改地址存储后,您正在访问现在无效的 foo。 3.使用valgrind并检查是否无效。
【讨论】:
以上是关于C 程序在指针运算后崩溃(仅在某些计算机中)的主要内容,如果未能解决你的问题,请参考以下文章
MFC 程序仅在某些 Windows 7 32 位计算机上存在运行时错误 R6025,并在其上安装 Visual Studio 后修复