c – 为什么抛出指向原始类的指针的奇怪行为?

假设在我的代码中我必须将void *存储为数据成员,并在需要时将其强制转换回原始类指针.为了测试它的可靠性,我写了一个测试程序( linux ubuntu 4.4.1 g -04-Wall),我很震惊地看到了这个行为.
struct A
{
  int i;
  static int c;
  A () : i(c++) { cout<<"A() : i("<<i<<")\n"; }
};
int A::c;

int main ()
{
  void *p = new A[3];  // good behavior for A* p = new A[3];
  cout<<"p->i = "<<((A*)p)->i<<endl;
  ((A*&)p)++;
  cout<<"p->i = "<<((A*)p)->i<<endl;
  ((A*&)p)++;
  cout<<"p->i = "<<((A*)p)->i<<endl;
}

这只是一个测试程序;实际上,对于我的情况,必须将任何指针存储为void *,然后将其强制转换回实际指针(借助模板).所以我们不要担心这一部分. output of the above code是,

p->i = 0
p->i = 0 // ?? why not 1
p->i = 1

但是如果你改变了void * p;到A * p;它给了expected behavior.为什么?

一个问题,我无法逃避(A *&),否则我不能使用操作符;但它也发出了警告,dereferencing type-punned pointer will break strict-aliasing rules.有没有可行的方法来克服警告?

解决方法

好吧,正如编译器警告你的那样,你违反了严格的别名规则,这正式意味着结果是未定义的.

您可以通过使用增量的函数模板来消除严格的别名冲突:

template<typename T>
void advance_pointer_as(void*& p,int n = 1) {
    T* p_a(static_cast<T*>(p));
    p_a += n;
    p = p_a;
}

使用此函数模板,main()的以下定义会在Ideone编译器上生成预期结果(并且不发出警告):

int main()
{
    void* p = new A[3];
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
    advance_pointer_as<A>(p);
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
    advance_pointer_as<A>(p);
    std::cout << "p->i = " << static_cast<A*>(p)->i << std::endl;
}

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...