0

这可能是一个已经被问过的非常基本的问题,但我不太确定这里的答案Casting an int pointer to a char ptr and反之亦然适用于我的情况。所以基本上我有以下几点:

void* head = sbrk(1024);  //allocate 1024 bytes in heap   

*((int*)(head+size)) = value;   //value and size are int with valoues between 1 and 1023

我想知道对于任意大小的值,上述是否不起作用,那么大小值的限制是什么?它必须能被4整除吗?

4

3 回答 3

2

首先,您不能对 void 指针进行指针运算。该代码甚至不应该编译。

为了便于讨论,让我们假设您有一个 char 指针。然后正式地,这样的强制转换后跟访问是未定义的行为。然而,在现实世界中,如果您可以手动确保对齐,您的代码将始终有效。您必须确保写入的地址位于对齐的内存位置,否则无法保证代码可以正常工作。


使用 ISO 9899:2011 标准中的相关引用进行编辑,为什么 void 指针上的指针算术是未定义的行为:

6.3.2.2 无效

不应以任何方式使用 void 表达式(具有 void 类型的表达式)的(不存在的)值,并且不应将隐式或显式转换(除了 void)应用于此类表达式。

.

6.5.6 加法运算符

/--/

另外,两个操作数都应具有算术类型,或者一个操作数应是指向完整对象类型的指针,而另一个应具有整数类型。(递增相当于加 1。)

.

4 一致性

如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”一词或省略任何明确的行为定义来表示。这三者在重点上没有区别;他们都描述了“未定义的行为”。

违反标准中的规范文本的代码是否“应该编译”当然可以辩论,但我认为讨论对 OP 没有好处。永远不要编写依赖于未定义行为的代码。

于 2013-03-25T07:20:46.567 回答
1

使用memcpy()

memcpy((char*)head + size, &value, sizeof(value));
于 2013-03-25T07:32:34.297 回答
0

在许多系统上,在这种情况下,它需要是size四的倍数(取决于下面详述的其他条件,包括int系统上的大小为四个字节)。在不需要这个的系统上,它通常是首选。

首先, 的类型headvoid *,C 标准没有定义使用 进行指针运算时会发生什么void *

一些编译器,尤其是 GCC 及其继承者,会将这种算术视为类型是char *. 我将在此基础上进行。

其次,我不知道sbrk返回具有任何特定对齐方式的地址的保证。

让我们假设它sbrk确实返回了一个对齐良好的地址,并且您的 C 实现做了简单的事情来评估* (int *) (head + size) = value,即发出存储指令将value(转换为int)的值写入地址head + size

那么你的问题就变成了:我的计算平台int对这个地址的商店做了什么?

只要head + size地址int在您的平台上适当对齐,商店就会按预期执行。在大多数平台上,四字节整数更喜欢四字节对齐,八字节整数更喜欢八字节对齐。只要head对齐到这个preferencesize的倍数并且是这个preference的倍数,那么store就会正常执行。

否则,会发生什么取决于您的平台。在某些平台上,硬件执行存储但可能比正常的存储指令执行得更慢,因为它将它分成两个单独的内存写入。(这也意味着共享相同内存的其他进程可能能够在一部分值已存储但另一部分未存储时读取内存。同样,这取决于您的计算平台的特性。)

在某些平台上,硬件会发出异常信号,中断程序执行并将控制权转移给操作系统。一些操作系统通过分析失败的指令并执行执行预期存储的替代指令来修复未对齐的存储(或者操作系统将异常中继到程序中的特殊代码,可能在自动包含的库中,这些代码执行此修复工作) . 在这些平台上,错位的店铺会很慢;它们会极大地降低程序的性能。

在某些平台上,硬件会发出异常信号,并且操作系统不会修复未对齐的存储。相反,操作系统要么终止您的进程,要么向它发送有关问题的信号,这通常会导致您的进程终止。(其他可能性包括触发调试器或输入您在程序中包含的特殊代码来处理信号。)

于 2013-03-25T11:49:23.427 回答