混叠和指针互转换性



给定以下代码:

struct Tag {};
struct X {
//    Tag t; // if not commented it shouldn't be pointer-interconvertible
int k;
};
int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}

生成的代码为:

fn(X const&, int&):
mov     eax, DWORD PTR [rdi]
mov     DWORD PTR [rsi], 2
add     eax, DWORD PTR [rdi]
ret

此处,编译器假定别名。

如果成员t不存在,则类型Xint是指针可相互转换的。因此,编译器必须生成代码,就好像引用可以别名一样。

但是,如果存在成员t,则它们不应再是指针可相互转换的,并且应生成非别名大小写的代码。但在这两种情况下,除了成员k的相对地址外,代码是相同的。

汇编程序:

fn(X const&, int&):
mov     eax, DWORD PTR [rdi+4]
mov     DWORD PTR [rsi], 2
add     eax, DWORD PTR [rdi+4]
ret

作为反例

template<typename T>
struct X {int k; };
int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}

在上面的版本中,生成的代码假定没有别名,但类型是指针可相互转换的。

fn(X<A>&, X<B>&):
mov     eax, DWORD PTR [rdi]
mov     DWORD PTR [rsi], 2
add     eax, eax
ret

谁能解释一下?

这里

int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}

编译器必须假定p可能是对x.k的引用。px.k都是类型int的左值。因此,它们可能相互混叠。无论X是否与int指针互转换,都不会改变p可能是对x.k的引用这一事实。

这里

int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}

另一方面,X<struct A>X<struct B>是完全不相关的类型。xp不能是对同一对象的引用。因此,x.kp.k不能表示同一个子对象。事实上,X<struct A>X<struct B>都可以与int进行指针互转换,这同样是无关紧要的......

这里

int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}

X::kintp是对int的引用。p可以是对x.k的引用。

另一方面,在这里:

int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}

X<struct A>X<struct B>是不同的类型。没有办法让xp或它的一部分引用同一个对象。

但是,如果 k 是私有的并且 X 有运算符 int(( 常量返回 k 怎么办?

然后什么都没有改变。说得很草率,你需要一个引用/指针来获得潜在的混叠。例如

struct G {};
struct H { G* g; }
void foo(G* a,H b);

在这里,b.ga可以指向相同的G(请注意,无论b是通过值、引用还是指针传递的,都是这种情况(。在您的示例中...

template<typename T>
struct X {int k; };
int fn(X<struct A>& x, X<struct B>& p)

.. 唯一的参考文献是xp.它们指的是不同类型的对象,也就是不同的对象。

相关内容

  • 没有找到相关文章

最新更新