C++:偏移类型


Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /www/wwwroot/fawdlstty.com/wp-content/plugins/wp-syntax/wp-syntax.php on line 383

地址偏移类型在C艹中算是偏冷门的技术,但在特定场合下可以节省大量的代码从而实现需求。这种类型的定义为:类或结构体中的数据成员相对于基址的偏移量。比如,一个类里面成员a地址相对于类基地址偏移量为4;成员b地址相对于类基地址偏移量为8等等。
示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
 
class A {
public:
    int a, b, c;
    A () : a (3), b (5), c (7) {}
};
 
int main (int argc, char* argv[]) {
    int (A::* x) = &A::a;
    int A::* y = &A::b;
    using TZ = int (A::*);
    TZ z = &A::c;    
 
    A *p = (A*)nullptr;
 
    cout << "地址偏移与偏移量值:" << endl;
    cout << &(p->a) << '\t' << &(p->*x) << endl;
    cout << &(p->b) << '\t' << &(p->*y) << endl;
    cout << &(p->c) << '\t' << &(p->*z) << endl;
 
    cout << "直接访问的结果:" << endl;
    cout << x << '\t' << y << '\t' << z << endl;
 
    return 0;
}

代码含义为:首先创建一个类,类里面有三个int类型成员属性,然后在main函数里面写了三种生成地址偏移类型的方法,其中第三种为首先构造地址偏移类型,然后用类型来定义。从经验上看,很容易看出偏移类型为0、4、8,实际运行结果也确实如此。
本机运行结果如下:
20160910151508
直接访问的结果有点出人意料,按道理说也应该是0、4、8才对,难道只代表一个符号么?
于是,在Disassembly上调试,为便于查看,我将代码改为cout << x;,以上代码反汇编结果为:
20160910152858
通过断点调试,x、y、z的值确实是0、4、8,另外反汇编代码可以明显看出,直接打印的含义为,如果值为0xFFFFFFFF,那么显示0,否则为1。因为通常不需要直接打印偏移长度,所以就把这个功能给省略了。真正需要用到的是,这个偏移是不是有效的。定义为,假如偏移长度为0xFFFFFFFF,那么代表这个偏移是无效的。于是我简单加了个hack:

1
2
__asm { mov x, 0ffffffffh }
cout << x;

代码不出所料,结果为0。这儿的0和1分别代表此处偏移类型是否有效。