怎样在编译期间求类成员的地址与this的偏移值?

孩皮妞野 2006-04-22 08:38:30
大体意思如下

class C{

int a;
char b;


const static int delta=/* your code to get the value
* of (char*)&this.b-(char*)this
* at complie time
*/
};

之所以有此一问是在g++中类似下面的代码发现了我没有预料的情况


class C{
struct S{
int func(...){
// 需要从S的this求出 C的this

}
};

int v;
S s; // 类C有且仅有一个S的实例, 在S::func中
// 需要从&this->s 反求出this的值
// 本来以为这个偏移值一定是-4, 结果发现g++中
// 居然是5
};
...全文
550 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
ytfrdfiw 2006-04-25
  • 打赏
  • 举报
回复
记得深入C++模型中有相关的解释。
孩皮妞野 2006-04-25
  • 打赏
  • 举报
回复
不满足这个条件:
>>不能有运行期的成本(空间和时间上都是)]

如果要做个函数来求类成员的offset, 办法太多了,不用去采取那种非常不标准的做法。

比如我说的
reinterpret_cast<int>( &reinterpret_cast<C*>(0)->b );

就可以了。可能这个的成本还更低一点。所以我没有去下MingGW去测试你的代码。

不管怎么说,谢谢你的热心参与。我会看着给分的。 :-)

pongba 2006-04-24
  • 打赏
  • 举报
回复
目前C++里面没有标准的途径获取成员在结构体中的偏移,更不用说还要是常量了。
唯一最为接近的方案是使用offsetof()宏,改宏的定义想必你也是知道的。然而,问题在于,虽说这个偏移量原则上来说是完全编译期确定的,然而由于语法上的缘故,就是没法让编译器把它“当成”编译期常量来对待。原因,如你所说,在于“&”上面,因为"&"不是个“编译期”操作符,所以其结果也就不是“编译期”的,而要想获得成员偏移,又不得不使用这个操作符。
结论是,现有标准下,没法。0x应该会解决这个问题,已经有这方面的proposal了。可以去commitee site上搜一下。
另外,我不确定你是否要这样的能力:

class C{

int a;
char b;

static const int delta;
};

const int C::delta = offsetof(C,b);

因为C++标准规定,在类内部初始化的const static int成员是“编译期常量”,对它的要求跟对模板无类型参数的要求一样,要求是编译期确定的才行。
然而,如果我们将其定义像普通的static成员一样,放至类外部,就没有了这个约束,这样一来仍然是const的,只不过不再是编译期的而已,这一结果唯一的影响也就是当它被用作模板参数时会报错而已,其余没啥。
yuanchuang 2006-04-24
  • 打赏
  • 举报
回复
我去看看c++ primer了 ,今天花了我80大洋买了一本  做为我升到四个裤衩的奖励//
-------------------
你才花了80啊?我怎么要115.2啊?
那老板小气的连两毛钱都不肯少……
yuanchuang 2006-04-24
  • 打赏
  • 举报
回复
谢谢chenhu_doc顶了一贴,粗心大意是我的老毛病,我居然贴上去的两个全是头文件,嘿嘿
//te.cpp
#include <iostream>
#include "te.h"
using namespace std;

int main()
{
C c;
int offset = c.getptos()->func();
cout << offset;
C * add = (C *)((int)(c.getptos()) - offset);
if (add == &c)
cout << "Equir";
else
cout << "Not equir!";
return 0;
}
chenhu_doc 2006-04-24
  • 打赏
  • 举报
回复
看看 把我们的原创给累的呀。。。。
楼主这招可是激发了不少人呀,对原创尤为明显,终于看见了这么有技术含量的原创的帖子。。。 长吐一口气先。。。。。
lz如果要继续,我不反对,,,,
原创也加油。。。。。
我去看看c++ primer了 ,今天花了我80大洋买了一本  做为我升到四个裤衩的奖励////
yuanchuang 2006-04-24
  • 打赏
  • 举报
回复
第二个是//te.cpp

反正这个在我的电脑上编译通过了,环境:MinGW2.05

我这次回复,不是为分而来。
yuanchuang 2006-04-24
  • 打赏
  • 举报
回复
为了证明我的正确性,我编了一个:

//te.h
class C{
struct S{
int func(){
// 需要从S的this求出 C的this
return (int)&C::s;
}
};

int v;
S s; // 类C有且仅有一个S的实例, 在S::func中
// 需要从&this->s 反求出this的值
//本来以为这个偏移值一定是-4, 结果发现g++中
//居然是5
public:
S *getptos()
{
return &s;
}
};



//te.h
class C{
struct S{
int func(){
// 需要从S的this求出 C的this
return (int)&C::s;
}
};

int v;
S s; // 类C有且仅有一个S的实例, 在S::func中
// 需要从&this->s 反求出this的值
//本来以为这个偏移值一定是-4, 结果发现g++中
//居然是5
public:
S *getptos()
{
return &s;
}
};
yuanchuang 2006-04-24
  • 打赏
  • 举报
回复
class C{
struct S{
int func(...){
// 需要从S的this求出 C的this
}
};

int v;
S s; // 类C有且仅有一个S的实例, 在S::func中
// 需要从&this->s 反求出this的值
// 本来以为这个偏移值一定是-4, 结果发现g++中
// 居然是5
};
-----------------------------------------
那我就这么说一遍,不知道是不是你想知道的意思:
你求的是成员偏移量。
如果编译器没有处理,v的偏移量是0,但你得出的结果是1;s的偏移量是4,但你得出的结果是5
否则,v的偏移量是0,你得出的结果是0;s的偏移量是4,你得出的结果是4。
struct S他的对象占一个字节的大小,但是他本身定义在class C中并不影响C对象的偏移量。
所以g++中得出的是5或4都很正常。

“类C有且仅有一个S的实例, 在S::func中”这对类的偏移量也不产生影响,因为它是一个函数而已,不是一个非静态成员,即使你的struct S中有成员又怎么样?他也不会对C的偏移量产生影响。在类中有编译量的只有非静态成员和一些虚拟指针之类而已。

不知道这次我理解你的意思没有,或者说我说的是错的。
孩皮妞野 2006-04-24
  • 打赏
  • 举报
回复
谢谢 pongba.

看起来这个问题暂时无解了。我现在是在每个类中记下自己用了多少,确定其immediate派生类的offset。 我的这个类体系除了根类有一个数据成员,其他的都没有真正的数据成员,但是封装的property会占用一个字节[至少在g++上],如果超过一个字节,这样的封装也真的没什么意义了。其他编译器还没有试,有印象borland的bcc32也是用1个字节。

好了元创, 既然你已经放弃了,我也就不给你了。 我真的怀疑你从头到尾有没有看懂过我的问题。所谓行家一伸手,就知道有没有,Piboye(柳月清) 和 pongba(刘未鹏|的回复,有的话不多,也可能没有解决问题,但是你能明白他们理解了你的问题。

这样吧,告诉我你用的MingGW的版本,贴上你的代码[可以放到我要求的那个地方,或者其他形式,但不能有运行期的成本(空间和时间上都是)], 如果我可以用那个版本的MinGW编译通过,我专门开个贴给你100分。


谢谢大伙了。
cunsh 2006-04-24
  • 打赏
  • 举报
回复

mark
xuexi;
yuanchuang 2006-04-23
  • 打赏
  • 举报
回复
楼主,你这50分得的太辛苦了……

我不知道是你没有理解我的意思还是我没有说清楚

算了……我放弃了……
yuanchuang 2006-04-22
  • 打赏
  • 举报
回复
解决了多给点分啊,哈哈
我想混星星=_+
yuanchuang 2006-04-22
  • 打赏
  • 举报
回复
MinGW

我没有拿你的测试,可是我编过类似的程序,但是在Dev-C++上就不管用了,嘿嘿

所以我说不一定编译器支持,我觉得VC6应该支持吧,但我没有在它上面用过。
孩皮妞野 2006-04-22
  • 打赏
  • 举报
回复
>>其实是4,

是的。我忘了我的那个类已经继承过一次了,基类中拥有个空union, 加了1个偏移;子类中又有一个空union, 所以冒出这么个奇怪的数5来。

你的办法应该是不管用的,告诉我你在那个编译器上测试成功了吧。
孩皮妞野 2006-04-22
  • 打赏
  • 举报
回复
换了个方式,更好的解决了这个问题:

#include <iostream>


class C{
int a[10];
};

struct Events{
struct Visible{
operator bool()const{
std::cout<<"in bool()const of Visible,calculated C2::this"
<<(void*)((char*)this-delta)<<std::endl;
}
};
struct Toggled{
operator bool()const{
std::cout<<"in bool()const of toggled,calculated C2::this"
<<(void*)((char *)this-delta)<<std::endl;
}
};

union{
Visible visible;
Toggled toggled;
};
const static int delta=sizeof(C);
};

class C2 :public C, public Events{

int i;

};

int main()
{
C2 m, n;

std::cout<<&m <<" "<<&n<<std::endl;

if(m.visible)
;

if(n.toggled)
;

}

yuanchuang 2006-04-22
  • 打赏
  • 举报
回复
更正一下,在g++中上面那个的偏移量确实是4,5是使用union后的情形……
------------------------------------
其实是4,但也很有可能是5,因为编译器要用1来区分偏移量为0时,这个到底是指向第一个成员还是初始化为0,但现在的一般的编译器对其作处理,所以结果一般是4,但当他是5时也不要惊讶,但在这种情况下,偏移量都需要-1才能用。从你的情况看,编译器已作处理了。

你按我的方法没有用吗?不会吧……
孩皮妞野 2006-04-22
  • 打赏
  • 举报
回复
前一点你可能是对了。

后一点你错了, 类中可以嵌套类声明的。

这个代码的目的在于模拟__property, 即把属性的set函数和get函数封装起来

举个例子:

class C{
struct Visible{
//Visible() //add default constructor if want to initialize to certain value
operator bool ()const{
return value;
}
bool operator=(bool v){
// 送出 before change的消息
value=v;
// 送出 after change 的消息
return value;
}
private:
bool value;
};


public:
Visible visible;
};


C c
有了上面的代码, 下面的代码都是合法的了

if(c.visible)
;

bool b=c.visible=false;

给end user的感觉就像一个成员变量一样亲切,而不是

if(c.get_visible)
;

c.set_visible(false);
bool b=c.get_visible();


而我碰到的问题是我要包装的是全局函数,比如
class C{
struct Visible{
//Visible() //add default constructor if want to initialize to certain value
operator bool ()const{
return some_global_function_which_rely_on_C_data( generate_C_this_from_this);
}
bool operator=(bool v){
// 送出 before change的消息
some_other_global_function_which_rely_on_C_data(generate_C_this_from_this,v);
// 送出 after change 的消息
return v;
}
//private:
// bool value; no longer required.
};


public:
Visible visible;
};



孩皮妞野 2006-04-22
  • 打赏
  • 举报
回复
class C{

int a;
char b;


const static int delta=/* put you code here. Don't wont any runtime burdon */;
};

错误消息:
`&' cannot appear in a constant-expression
孩皮妞野 2006-04-22
  • 打赏
  • 举报
回复
>>
还有个
const static int delta=/* your code to get the value
* of (char*)&this.b-(char*)this
* at complie time
*/
这是不可能的,static成员不可以获得对象的this地址,它只可以获得一般的地址。
static的这个声明的域内不可能有this指针。
<<


this 指针不是问题。可以认为任意位置是一个该类的对象,比如

offset=reinterpret_cast<C*>(0) - & reinterpret_cast<C*>(0)->b



,关键是常量表达式中不能有&运算。


但是从这个问题的实质来看,这个offset可能因编译器而异,但确实是一个编译期间决定的常量

加载更多回复(6)

64,282

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧