指针类型强制转换会改变非预期内存
Pointer type casting altering unintended memory
#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()的原型之外,上述所有代码都是可以更改的。错误在这里:
for ( unsigned long i = 0; i < DataSize; i++)
{
// vvvvvvvvvv vvvvvvvvvv
*(Destination + i*DataSize) = *(Source + i*DataSize);
}
i * DataSize
总是大于i
=> "越界"访问
替换为:
for ( unsigned long i = 0; i < DataSize; i++)
{
*(Destination + i) = *(Source + i);
}
您将单个float
的地址传递给Read
(&Dest
),然后继续将许多值写入连续的内存位置。因为你写的是随机内存在这一点上,它不太可能覆盖index
(和其他东西),因为堆栈通常向下增长。
这是错误的:
*(Destination + i*DataSize) = *(Source + i*DataSize);
你想复制DataSize
相邻的字节,而不是DataSize
分开的字节(total span DataSize*DataSize
)
只是说
Destination[i] = Source[i];
一种有趣的(对我来说)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 );
但这是不必要的。
这是整个框架。
但是我觉得写这个很有趣
让我们仔细看看你的Read()
: i从0到DataSize-1的变化;每次访问内存的偏移量为i*DataSize…即,从0到DataSize*(DataSize-1)的偏移量。看起来不对,因为DataSize**2-DataSize
没有意义。
不像其他答案,我不想猜你想要什么。只是展示一种"维度分析",可以帮助发现代码中最错误的部分,而无需读取作者的思想
您将在fun()
中声明的标量变量Dest
视为Read()
中的数组。似乎Dest
和Index
变量都放在堆栈上相邻,这解释了Index
在Read()
内的循环为i==1
执行时被覆盖。
所以解决方案是:将Dest
也声明为数组:
float Dest[ARRAY_SIZE];
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 变量没有改变?通过向量的函数调用
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 为什么结构数组的内存集会改变程序行为
- 为什么这些内存值在GDB中永远不会改变
- std::list会改变元素在内存中的位置吗?
- 是否有一种方法可以改变变量在内存中的存储方式(位大小)
- CYGWIN:内存中的变量自发地改变值
- 指针类型强制转换会改变非预期内存
- 动态数组改变内存地址位置