我可以用分配的内存做我想做的事

时间:2017-01-26 11:26:15

标签: c pointers malloc strict-aliasing

我可以对分配的内存做些什么限制?(标准方式)

例如

#include <stdio.h>
#include <stdlib.h>

struct str{
    long long a;
    long b;
};

int main(void) 
{
    long *x = calloc(4,sizeof(long));
    x[0] = 2;
    x[3] = 7;
//is anything beyond here legal( if you would exclude possible illegal operations)
    long long *y = x; 
    printf("%lld\n",y[0]); 
    y[0] = 2;
    memset (x,0,16);
    struct str *bar = x;
    bar->b =  4;
    printf("%lld\n",bar->a); 
    return 0;
}

总结:

  • 只要大小合适,我可以重命转指向其他数据类型和结构的指针吗?
  • 我可以在写作之前阅读吗?
  • 如果不能,我写完后可以阅读吗?
  • 我可以使用小于分配内存的结构吗?

3 个答案:

答案 0 :(得分:4)

y[0]读取违反严格别名规则。您使用类型为long long的左值来读取有效类型long的对象。

假设你省略了那条线;下一个麻烦的部分是memset(x,0,16);This answer认为memset不会更新有效类型。标准尚不清楚。

假设memset保持有效类型不变;下一期是阅读bar->a

C标准也不清楚。有人说bar->a暗示(*bar).a,这是严格的别名违规,因为我们没有先将bar对象写入该位置。

其他人(包括我)说它很好:用于访问的唯一左值是bar->a;这是long long类型的左值,它访问有效类型为long long的对象(由y[0] = 2;写入的对象)。

有一个C2X工作组致力于改进严格别名的规范,以澄清这些问题。

答案 1 :(得分:3)

  

我可以重命名指向其他数据类型的指针,只要大小合适吗?

您可以将 1 重新转换为与您分配的内存一样大的任何数据类型。但是,您必须根据6.5p6

更改值以更改所有涂层对象的有效类型
  

我可以在写作之前阅读吗?   如果没有,我可以在写完后阅读吗?

没有。除非另有指定(否则为calloc 2 ,否则内存中的值是不确定的。它可能包含陷阱值。为了将值重新解释为另一种类型的强制转换是UB,违反严格别名(6.5p7

  

我可以使用小于分配内存的结构吗?

是的,但那是浪费。

1 您需要先转换为void*。否则,您将从编译器获得有关不兼容指针类型的合理投诉 2 即使这样,某些类型也可能陷入完全0位模式,因此它取决于。

答案 2 :(得分:0)

大多数编译器都提供一种模式,在这种模式下,指针的读取和写入将按照执行的顺序作用于底层存储,而不管涉及的数据类型如何。标准不要求编译器提供这样的模式,但据我所知,所有质量编译器都这样做。

根据他们公布的理由,标准的作者在语言中添加了别名限制,其目的是避免编译器在给定代码时做出悲观的别名假设:

float f;
float test(int *p)
{
  f=1.0f;
  *p = 2;
  return f;
}

请注意,在基本原理中给出的示例[非常类似于上述],即使通过指针f修改p使用的存储是合法的,也是一个合理的人看着代码没有理由认为这样的事情可能会发生。另一方面,许多编译器编写者认识到如果给出类似的东西:

float f;
float test(float *p)
{
  f=1.0f;
  *(int*)p = 2;
  return f;
}

人们必须刻意地认为代码不太可能修改float使用的存储,因此没有理由认为质量编译器不应该将写入视为{{1作为对*(int*)p的潜在写入。

不幸的是,在这几年中,编译器编写者越来越积极地使用基于类型的别名“优化”,有时会以明显无可否认的方式超出标准允许的范围。除非程序永远不需要在不同时间以不同类型访问任何存储,否则我建议在支持它的编译器上使用float选项。否则,可能有一个符合标准的代码并且今天可以运行,但是在未来版本的编译器中失败了,它的“优化”变得更加激进。

PS - 在某些情况下,禁用基于类型的别名可能会影响代码的性能,但正确使用-fno-strict-aliasing - 合格的变量和参数应该可以避免悲观别名假设的成本。稍微小心一点,使用这些限定符可以实现与积极混叠相同的优化,但更安全。