指针式铸造改变了意外的记忆

时间:2013-01-10 22:06:55

标签: c++

#define ARRAY_SIZE 20

float DataSource[ARRAY_SIZE];

void Read(unsigned char const *Source, unsigned char *Destination, unsigned long DataSize)
{
  for ( unsigned long i = 0; i < DataSize; i++)
  {
    *(Destination + i*DataSize) = *(Source + i*DataSize);
  }
}

void fun()
{
  int Index;
  float Dest;

  for ( Index = 0; Index < ARRAY_SIZE; Index++ )
  {
    Read((unsigned char *)&DataSource[Index], (unsigned char *)&Dest, sizeof(DataSource[Index]));
  }
}

我遇到上述代码的问题,在调用Read()时,我的Index变量被覆盖,我确定丑陋的指针转换是罪魁祸首,但我无法理解究竟发生了什么。

unsigned char指针类型是必需的,因为上面的代码旨在模拟某些驱动程序级软件并维护相同的原型。

有人可以帮我理解这个问题吗?除了Read()原型之外,上述所有代码都是可以改变的。

6 个答案:

答案 0 :(得分:4)

错误在于:

for ( unsigned long i = 0; i < DataSize; i++)
{
  //              vvvvvvvvvv               vvvvvvvvvv
  *(Destination + i*DataSize) = *(Source + i*DataSize);
}

i * DataSize始终大于i =&gt; “出界”访问。

替换为:

for ( unsigned long i = 0; i < DataSize; i++)
{
  *(Destination + i) = *(Source + i);
}

答案 1 :(得分:2)

您将单个float的地址传递给Read&Dest),然后继续向连续的内存位置写入多个值。由于你正在编写随机内存,因此它不可能覆盖index(和其他东西),因为堆栈通常会向下扩展。

答案 2 :(得分:1)

这是错误的:

*(Destination + i*DataSize) = *(Source + i*DataSize);

您希望复制DataSize个相邻字节,而不是DataSize个字节{总范围DataSize*DataSize

说完

Destination[i] = Source[i];

答案 3 :(得分:1)

一种有趣的(对我而言)C ++方式。

template<typename Data>
struct MemBlockRefHelper {
  typedef Data value_type;
  Data* data;
  size_t size;
  MemBlockRefHelper( Data* d, size_t s):data(d), size(s) {}

  template<typename Target, typename Other=typename Target::value_type>
  Target& Assign( MemBlockRefHelper<Other> const& other ) {
    Assert(size == other.size);
    for (size_t i = 0; i < size; ++i) {
      if (i < other.size) {
        data[i] = other.data[i];
      } else {
        data[i] = 0;
      }
    }
    Target* self = static_cast<Target*>(this);
    return *self;
  }

};
struct MemBlockRef;
struct MemBlockCRef:MemBlockRefHelper<const unsigned char> {
  MemBlockCRef( const unsigned char* d, size_t s ):MemBlockRefHelper<const unsigned char>( d, s ) {}
  MemBlockCRef( const MemBlockRef& other );
};
struct MemBlockRef:MemBlockRefHelper<unsigned char> {
  MemBlockRef( unsigned char* d, size_t s ):MemBlockRefHelper<unsigned char>( d, s ) {}
  MemBlockRef& operator=( MemBlockRef const& other ) {
    return Assign< MemBlockRef >( other );
  }
  MemBlockRef& operator=( MemBlockCRef const& other ) {
    return Assign< MemBlockRef, const unsigned char >( other );
  }
};
inline MemBlockCRef::MemBlockCRef( const MemBlockRef& other ): MemBlockRefHelper<const unsigned char>( other.data, other.size ) {}

void Read( unsigned char const* Source, unsigned char* Dest, unsigned long DataSize ) {
  MemBlockCRef src( Source, DataSize );
  MemBlockRef dest( Dest, DataSize );
  dest = src;
}

大量过度设计,但想法是结束一定大小的POD内存块的想法,并为其内容提供引用语义(初始化是创建对相同数据的新引用,赋值做副本超过提到的数据)。

一旦你有了这样的课程,Read的代码就成了3班。好吧,你可以在一个地方做到这一点:

  MemBlockRef( Dest, DataSize ) = MemBlockCRef( Source, DataSize );

但这是不必要的。

嗯,这就是整个框架。

但我写这篇文章很有趣。

答案 4 :(得分:0)

让我们仔细看看你的Read():我从0变为DataSize-1;每次通过i * DataSize的偏移量访问内存时,即从0到DataSize *(DataSize-1)的偏移量。看起来不对,因为DataSize**2-DataSize毫无意义。

与其他答案不同,我不想猜猜你想要什么。只是展示一种“维度分析”,可以帮助发现代码的最大部分,而无需阅读作者的想法。

答案 5 :(得分:0)

您将Dest内声明的标量变量fun()视为Read()内的数组。似乎Dest和您的Index变量都放在堆栈旁边,这说明Index在为Read()执行i==1内的循环时会被完全覆盖}。

所以解决方案是:将Dest声明为数组:

float Dest[ARRAY_SIZE];