- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在阅读文章Member Function Pointers and the Fastest Possible C++ Delegates来自 Don Clugston 并且自己正在试验这些东西,但无法正确复制案例。
当然,Don Clugston 的代码是未定义的行为。
这特别是关于 GCC 对成员函数指针的表示。
这是关于 GCC 成员函数表示的文章中的一段代码片段(从文章中照原样复制,不是实际代码,甚至不要编译):
// GNU g++ uses a tricky space optimisation, also adopted by IBM's VisualAge and XLC.
struct GnuMFP {
union {
CODEPTR funcadr; // always even
int vtable_index_2; // = vindex*2+1, always odd
};
int delta;
};
adjustedthis = this + delta
if (funcadr & 1) CALL (* ( *delta + (vindex+1)/2) + 4)
else CALL funcadr
delta
值得我去试验它。
delta
仍然存在,因为成员函数指针的大小仍然是两个指针的大小。另外,根据我的观察,vtable 索引技巧今天仍然适用。
#include <cstring>
#include <iostream>
#include <iomanip>
void print_pointer(auto const ptr) {
alignas(alignof(ptr)) std::byte memory[sizeof(ptr)];
std::memcpy(memory, std::addressof(ptr), sizeof(ptr));
auto until_newline = int{8};
for (auto const b : memory) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<std::uint16_t>(b);
if (--until_newline == 0) {
until_newline = 8;
std::cout << '\n';
}
}
}
// No inheritance, simplest possible
namespace test1 {
struct S {
char a;
void method() const& {
std::cout << "test1 S";
}
};
}
// Simple inheritance, non polymorphic
namespace test2 {
struct B1 { char a; };
struct S : B1 {
char a;
void method() const& {
std::cout << "test1 S";
}
};
}
// Multiple inheritance, non polymorphic
namespace test3 {
struct B1 { char a; };
struct B2 { char a; };
struct S : B1, B2 {
char a;
void method() const& {
std::cout << "test1 S";
}
};
}
// Multiple inheritance, non polymorphic, function in the middle
namespace test4 {
struct B1 { char a; };
struct B2 {
char a;
void method() const& {
std::cout << "test1 S";
}
};
struct S : B1, B2 { char a; };
}
// Simple inheritance, polymorphic
namespace test5 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct S : B1 {
void method() const& override {
std::cout << "test1 S";
}
};
}
// Multiple inheritance, polymorphic, one base only
namespace test6 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct B2 {
char a;
};
struct S : B1, B2 {
void method() const& override {
std::cout << "test1 S";
}
};
}
// Multiple inheritance, polymorphic, two base
namespace test7 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct B2 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct S : B1, B2 {
void method() const& override {
std::cout << "test1 S";
}
};
}
// Simple virtual inheritance, non polymorphic
namespace test8 {
struct B1 { char a; };
struct S : virtual B1 {
void method() const& {
std::cout << "test1 S";
}
};
}
// Simple virtual inheritance, polymorphic
namespace test9 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct S : virtual B1 {
void method() const& override {
std::cout << "test1 S";
}
};
}
// Multiple with one virtual inheritance, one polymorphic
namespace test10 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct B2 {
char a;
};
struct S : B1, virtual B2 {
void method() const& override {
std::cout << "test1 S";
}
};
}
// Multiple with both virtual inheritance, both polymorphic
namespace test11 {
struct B1 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct B2 {
char a;
virtual void method() const& {
std::cout << "test1 S";
}
};
struct S : virtual B1, virtual B2 {
void method() const& override {
std::cout << "test1 S";
}
};
}
int main() {
print_pointer(&test1::S::method);
std::cout << '\n';
print_pointer(&test2::S::method);
std::cout << '\n';
print_pointer(&test3::S::method);
std::cout << '\n';
print_pointer(&test4::S::method);
std::cout << '\n';
print_pointer(&test5::S::method);
std::cout << '\n';
print_pointer(&test6::S::method);
print_pointer(&test6::B1::method);
std::cout << '\n';
print_pointer(&test7::S::method);
print_pointer(&test7::B1::method);
print_pointer(&test7::B2::method);
std::cout << '\n';
print_pointer(&test8::S::method);
std::cout << '\n';
print_pointer(&test9::S::method);
print_pointer(&test9::B1::method);
std::cout << '\n';
print_pointer(&test10::S::method);
print_pointer(&test10::B1::method);
std::cout << '\n';
print_pointer(&test11::S::method);
print_pointer(&test11::B1::method);
print_pointer(&test11::B2::method);
}
在我所有的例子中,成员函数指针的最后 8 个字节是
0000000000000000
这是完整的输出:
b013400000000000 0000000000000000
f013400000000000 0000000000000000
3014400000000000 0000000000000000
d013400000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
1014400000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
0100000000000000 0000000000000000
Live example
最佳答案
我没有看过 GCC 代码,所以我只是在做一些猜测和假设。
delta 用于调整 this
指针。所以我们必须构建一个案例,其中:
MyClass* pThis = ...;
MemberFunctionPointer mfp = ...;
(pThis->*mfp)(); // must adjust this := pThis + delta
为什么会
this
(成员函数内部的this指针)不同于
pThis
?如果我们从不同的类调用成员函数,就会发生这种情况:
struct B1
{
char c;
};
struct B2
{
char d;
void memfun();
};
struct S : B1, B2
{
void direct();
};
当你做类似的事情时
B2 b2;
b2.memfun();
那么我们就不用调整
this
指针,
this := &b2
.换句话说,
B2::memfun
预计
this
指向(子)对象的指针
B2
.
B2
在
S
类型的对象内被
B1
抵消.因此,当我们写
S s;
s.memfun();
编译器必须从
&s
调整地址至
&s.d
有效 - 它应用了增量。
using Smfp = void(S::*)();
Smfp m = &S::memfun; // it's really B2::memfun!
S s;
(s.*m)(); // we're calling B2::memfun, therefore we need to adjust this := &s + delta == &s.d
注意我们可以写
m = &S::direct;
(s.*m)(); // calls S::direct, no adjustment, this := &s
这解释了为什么我们需要将增量存储为成员函数指针的一部分。
using B2mfp = void(B2::*)();
B2mfp x = &B2::memfun; // x has no delta!
B2 b;
(b.*x)(); // no need to adjust, this := &b
&S::memfun
的类型实际上是
void(B2::*)()
因为这就是成员函数的继承方式:查找首先搜索
S
然后是它的基础。没有专用
S::memfun
(没有代码),真的只有
B2::memfun
我们也可以通过名称/别名
S::memfun
找到它.
关于c++ - 什么时候在 GCC 上的成员函数指针中使用增量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69647229/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我在64位linux下使用c++,编译器(g++)也是64位的。当我打印某个变量的地址时,例如一个整数,它应该打印一个 64 位整数,但实际上它打印了一个 48 位整数。 int i; cout <<
我是一名优秀的程序员,十分优秀!