我想将类的一部分复制到缓冲区。如果类中有更改,我需要这样做才能查看,并通过网络发送它以更新服务器上的更改。
我创建了一个可以备份和恢复类的模板类。现在我正在制作“寻找差异”功能。我希望用户可以定义内存块的大小。这会将类分成几部分,并且需要更少的数据发送。
问题是我无法将类内存的一部分复制到堆中,我无法正确获取地址。如果我做“班级地址”+“0x04”。然后我没有得到正确的地址。
这是我做的一个问题:
testclass test1;
testclass test2;
test1.set(1,1);
test2.set(1,2);
cout << &test1 << " " << (&test1 + 0x04) << endl; //0018FF24 0018FF44
memcpy(&test2,&test1 + 0x04,4);
test2.echo(); //Wrong data!
标题:
class testclass
{
int test,test2;
public:
void set(int a, int b) {test = a, test2 = b;}
void echo() {cout << test << " " << test2 << endl;}
};
我希望有人帮我解决这个问题。
谢谢!
答案 0 :(得分:2)
基本上,你不能用这样的指针捣乱。你通常不能依赖编译器巧合地将有意义的数据放在那里。
如果你想要成员的地址,你应该写&(test1.test2)
而不是&test1+0x04
因为即使 IF 一个int是4个字节而 IF 编译器没有填充结构, IF 你或其他人没有更改类的内容,那么&test1+0x04
实际上意味着“&test1
加4*sizeof(test)
字节“,这是在指针数组等价方面达到(&test1)[4]
的另一种方式。
另外,除非是POD,否则你不能memcpy
一般地超过课程并期望有意义的结果。
如果你想比较一个类的实例,你应该编写一个函数来依次比较每个成员。
您不能为此编写通用方法,因为C ++不是反射语言。这意味着你不能编写神奇地知道类成员名称和类型的代码。
因此,如果你想比较和修补这样的数据,你需要做这样的事情:
struct Foo {
int a;
int b;
void export_differences (std :: ostream & o, const Foo & f) {
if (a != f.a) o << "a " << f.a << " ";
if (b != f.b) o << "b " << f.b << " ";
o << ";";
}
void import_differences (std :: istream & i) {
std :: string s;
while (i >> s) {
if (s == "a") i >> a;
else if (s == "b") i >> b;
else if (s == ";") break;
else throw std :: runtime_error ("bad input");
}
}
};
您必须为要修补的每个课程编写类似的内容。
答案 1 :(得分:0)
魔法0x04和4来自哪里?
如果这样可行,那只是因为特定的对齐和实现。 更好的结构化方式:
class testclass
{
int test,test2;
public:
void set(int a, int b) {test = a, test2 = b;}
void echo() {cout << test << " " << test2 << endl;}
void backup_to(testclass& s)
{ s.test2 = test2; }
bool has_changed_respect(const testclass& s)
{ return s.test2 == test2; }
friend std::ostream& operator<<(std::ostream& s, const testclass& a)
{ return s << "testclass["<<&a<<"]: test="<<a.test<<", test2="<<a.test2<< std::endl; }
};
int main()
{
testclass t1, t2;
t1.set(1,1);
t2.set(3,4);
std::cout << t1 << t2;
t1.backup_to(t2);
std::cout << t2;
t1.set(5,6);
cout << t1 << t2 << t1.is_changed_respect(t2) << std::endl;
return 0;
}
答案 2 :(得分:0)
&test1 + 0x04
表示将testclass
大小的4倍添加到test1
的地址,结果指针的类型为testclass*
。它将指向数组的第五个元素,其第一个元素位于test1
的地址,除了test1
不是数组的一部分,因此添加具有未定义的行为。
您似乎想要的是将{字节添加到test1
的地址。例如,您可以使用((char*)&test1) + 4
执行此操作,这会生成类型为char*
的指针。请注意,标准不保证sizeof(int)
为4,也不保证offsetof(testclass, test2) == sizeof(int)
。
您可以将任何对象的内存检查为char*
或unsigned char*
。但是这种能力有多大的限制:
答案 3 :(得分:0)
1)首先,您需要将您的班级设为POD。至少你可以把数据成员分成单独的结构。
2)然后,如果需要选择偏移粒度= 1,2,4或2 ^ n个字节;并确定适合此要求的类型:2^n == sizeof(chunk_type)
。例如,您希望进行逐字节比较,因此将指针_State
(或MyClass
见#1)指向所需类型:(char *)this-&gt; m_state。
这是函数,它试图找到两个类中不同的第一个块,如果没有找到差异则返回它的偏移量或-1。
class MyClass {
struct _State {
int a,b
};
_State m_state;
public:
typedef char chunk_type;
int next_diff_pos(const MyClass& other, size_t offset = 0) const {
chunk_type *pThis = &m_state,
*pOther = &other.m_state;
if (offset < sizeof(_State)) {
size_t n = offset;
while(*pThis++ == *pOther++ && n < sizeof(_State))
n++;
// We need to test this again, because of ambigous while condition
if (n < sizeof(_State))
return n;
}
return -1;
}
};
PS:当然,你的chunk_type
必须定义==
运算符(这已经为char,int和其他标量完成了。)
(我没有测试过代码)