【发布时间】:2014-06-28 06:03:02
【问题描述】:
严格的别名防止我们使用不兼容的类型访问相同的内存位置。
int* i = malloc( sizeof( int ) ) ; //assuming sizeof( int ) >= sizeof( float )
*i = 123 ;
float* f = ( float* )i ;
*f = 3.14f ;
根据 C 标准,这将是非法的,因为编译器“知道”int 不能被 float 左值访问。
如果我使用该指针指向正确的内存会怎样,如下所示:
int* i = malloc( sizeof( int ) + sizeof( float ) + MAX_PAD ) ;
*i = 456 ;
首先我为int、float 分配内存,最后一部分是内存,它允许float 存储在对齐的地址上。 float 需要以 4 的倍数对齐。MAX_PAD 通常是 16 个字节中的 8 个,具体取决于系统。无论如何,MAX_PAD 足够大,所以float 可以正确对齐。
然后我将int 写入i,到目前为止一切顺利。
float* f = ( float* )( ( char* )i + sizeof( int ) + PaddingBytesFloat( (char*)i ) ) ;
*f= 2.71f ;
我使用指针i,将其增加int 的大小,并将其与函数PaddingBytesFloat() 正确对齐,该函数返回对齐float 所需的字节数,给定地址。然后我在里面写一个浮点数。
在这种情况下,f 指向不重叠的不同内存位置;它有不同的类型。
以下是标准 (ISO/IEC 9899:201x) 6.5 的一些部分,我在编写此示例时所依赖的部分。
别名是指多个左值指向同一内存位置。标准要求这些左值具有与对象的有效类型兼容的类型。
什么是有效类型,引用标准:
访问其存储值的对象的有效类型是声明的类型 对象,如果有的话。87) 如果一个值通过 左值的类型不是字符类型,则左值的类型变为 该访问和不修改的后续访问的对象的有效类型 存储的值。如果一个值被复制到一个没有声明类型的对象中 memcpy 或 memmove,或复制为字符类型的数组,则为有效类型 为该访问和后续访问不修改 value 是从中复制值的对象的有效类型(如果有的话)。对于没有声明类型的对象的所有其他访问,对象的有效类型是 只是用于访问的左值的类型。
87) 分配的对象没有声明类型。
我正在尝试连接各个部分并确定是否允许这样做。在我的解释中,分配对象的有效类型可以根据该内存上使用的左值的类型进行更改,因为这部分:For 对没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。
这合法吗?如果不是,如果我在第二个示例中使用 void 指针作为左值而不是 int 指针 i 会怎样?如果即使这样也行不通,如果我将分配给第二个示例中的浮点指针的地址作为 memcopied 值获取,并且该地址以前从未用作左值。
【问题讨论】:
-
你为什么要把应该简单的事情复杂化?使用结构并快乐!
-
为什么要编写难以阅读和维护的代码?
-
您是专门询问这是否合法,还是只是在寻找意见?
-
“在这种情况下,f 指向不重叠的不同内存位置;它具有不同的类型。” 它重叠(部分)
i[1]和/或i[2]. -
@Neil:来吧!这样做有很多原因,毕竟 C 是一种低级语言:实现内存分配器或内存区域、垃圾收集器、可变参数类型、解释器的类型系统、虚拟 CPU。 .. 在某些情况下,您可能会使用联合,但并非全部使用。并且知道语言在哪里设置限制总是有用的。
标签: c memory standards strict-aliasing