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



我可以对分配的内存做什么有限制吗?(标准)

例如

#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("%lldn",y[0]); 
y[0] = 2;
memset (x,0,16);
struct str *bar = x;
bar->b =  4;
printf("%lldn",bar->a); 
return 0;
}

总结:

  • 只要大小合适,我可以将指针重新转换为其他数据类型和结构吗
  • 那么,我可以先读后写吗
  • 如果不能,我可以在写作后阅读吗
  • 我可以将它与小于分配内存的结构一起使用吗

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

假设你省略了那一行;下一个麻烦的部分是CCD_ 4。这个答案认为memset不会更新有效类型。标准不明确。

假设CCD_ 6保持有效类型不变;下一个问题是CCD_ 7的读取。

C标准对此也不明确。有些人说bar->a意味着(*bar).a,这是一种严格的混叠冲突,因为我们没有首先将bar对象写入该位置。

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

有一个C2X工作组正在改进严格混叠的规范,以澄清这些问题。

只要大小合适,我可以将指针重新转换为其他数据类型吗?

您可以将1重写为最多与您分配的内存一样大的任何数据类型。但是,您必须写入一个值,才能根据6.5p6 更改全涂层对象的有效类型

那么,我可以先读后写吗
如果不能,我可以在写完之后阅读吗?

否。除非另有规定(calloc为其他)2,否则存储器中的值是不确定的。它可能包含陷阱值。将一个值重新解释为另一种类型的强制转换是UB,违反了严格的混叠(6.5p7)

我可以将它与小于分配内存的结构一起使用吗?

是的,但那是浪费。


1您需要先转换为void*。否则,编译器会对不兼容的指针类型提出合理的抱怨
2即使这样,某些类型也可能捕获完全为0位的模式,因此这取决于情况。

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

根据他们发表的基本原理,标准的作者在语言中添加了混叠限制,目的是避免编译器在给定以下代码时做出悲观的混叠假设:

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

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

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

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

不幸的是,在这几年里,编译器编写人员对基于类型的别名"优化"越来越积极,有时甚至明显且不可否认地超出了标准的允许范围。除非一个程序永远不需要在不同的时间以不同的类型访问任何存储,否则我建议在支持它的编译器上使用-fno-strict-aliasing选项。否则,一个程序可能有符合标准的代码,现在可以使用,但在未来版本的编译器中失败,因为它的"优化"变得更加激进。

PS——在某些情况下,禁用基于类型的混叠可能会影响代码的性能,但正确使用restrict限定的变量和参数应该避免悲观混叠假设的代价。只要稍微注意一下,使用这些限定符将实现与激进别名相同的优化,但要安全得多。

相关内容

  • 没有找到相关文章