有没有办法使用g ++编译器或任何其他方法打印C++对象的布局.一个简化的例子(假设int需要4个字节)
class A{
int a;
};
class B:public A{
int b;
}
Run Code Online (Sandbox Code Playgroud)
所以输出就是
A-
0 4
+ a +
B-
0 4 8
+ A.a + b +
Run Code Online (Sandbox Code Playgroud)
理解对象的布局(在我的例子中是虚拟机代码)会很有用.
提前致谢.
问候,扎赫尔
我刚刚学习了函数指针(指向存储函数机器代码的地址的指针).这让我想到机器代码以及它如何存储在内存中.
机器代码是否连续存储在内存中,以便可以"手动"增加指针,直到它指向下一个/上一个函数?
这是调试器的作用吗?他让我"看到"程序计数器指向机器代码的位置?
结论:可以用函数指针编程一个原始调试器吗?
我理解这是对的,还是我离开了?
跟进为什么ELF执行入口点虚拟地址为0x80xxxxx而不是0x0?和为什么Linux程序的虚拟内存地址为0x8048000开始?,为什么我不能ld使用与默认值不同的入口点ld -e?
如果我这样做,我会得到一个segmentation fault返回代码139,即使对于默认入口点附近的地址.为什么?
编辑:
我会更具体地提出这个问题:
.text
.globl _start
_start:
movl $0x4,%eax # eax = code for 'write' system call
movl $1,%ebx # ebx = file descriptor to standard output
movl $message,%ecx # ecx = pointer to the message
movl $13,%edx # edx = length of the message
int $0x80 # make the system call
movl $0x0,%ebx # the status returned by 'exit'
movl $0x1,%eax # eax = code for …Run Code Online (Sandbox Code Playgroud) 我正在尝试在C#中优化解析器组合器.当序列化格式与内存格式匹配时,一种可能的优化是仅对要在实例上解析的数据的(不安全)memcpy或甚至该类型的许多实例进行解析.
我想编写代码来确定内存中的格式是否与序列化格式匹配,以便动态确定是否可以应用优化.(显然这是一个不安全的优化,可能无法解决一大堆微妙的原因.我只是在尝试,而不是计划在生产代码中使用它.)
我使用属性[StructLayout(LayoutKind.Sequential,Pack = 1)]强制不填充并强制内存顺序匹配声明顺序.我用反射检查该属性,但实际上所有这些都证实是"无填充".我还需要字段的顺序.(我非常希望不必为每个字段手动指定FieldOffset属性,因为这样很容易出错.)
我假设我可以使用GetFields返回的字段顺序,但文档明确指出订单未指定.
鉴于我使用StructLayout属性强制字段的顺序,有没有办法反映该排序?
编辑我很好,所有字段必须是blittable的限制.
我知道你可以MemoryLayout<T>.size用来获得一个类型的大小T.
例如: MemoryLayout<Int32>.size // 4
但是,对于类实例(对象),MemoryLayout<T>.size返回对象的引用大小(64位计算机上的8个字节),而不是堆上实际对象的大小.
class ClassA { // Objects should be at least 8 bytes
let x: Int64 = 0
}
class ClassB {// Objects should be at least 16 bytes
let x: Int64 = 0
let y: Int64 = 0
}
MemoryLayout<ClassA>.size // 8
MemoryLayout<ClassB>.size // 8, as well :(
Run Code Online (Sandbox Code Playgroud)
如何获得物体的大小?
对于那些想知道的人,我没有真正的需要,我只是在探索Swift及其与C的互操作性.
有这个代码:
#include <iostream>
class Base
{
public:
Base() {
std::cout << "Base: " << this << std::endl;
}
int x;
int y;
int z;
};
class Derived : Base
{
public:
Derived() {
std::cout << "Derived: " << this << std::endl;
}
void fun(){}
};
int main() {
Derived d;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Base: 0xbfdb81d4
Derived: 0xbfdb81d4
Run Code Online (Sandbox Code Playgroud)
但是,当Derived类中的函数'fun'更改为virtual时:
virtual void fun(){} // changed in Derived
Run Code Online (Sandbox Code Playgroud)
然后,'this'的地址在两个构造函数中都不相同:
Base: 0xbf93d6a4
Derived: 0xbf93d6a0
Run Code Online (Sandbox Code Playgroud)
另一件事是如果类Base是多态的,例如我添加了一些其他虚函数:
virtual void funOther(){} // added to Base
Run Code Online (Sandbox Code Playgroud)
那么'this'匹配的地址再次: …
如果我有一个类Base,至少有一个虚函数,并且一个Derived类从中单独继承,(uintptr_t)derived - (uintptr_t)static_cast<Base*>(derived)则保证(由Itanium ABI)为零,即使Derived不是标准布局.然而,在一般情况下,这不一定是真的(例如,多重继承).
是否有可能编写一个特征,可用于检测一个类是否是另一个类的主要基类?
来自Itanium ABI的有用部分:
http://refspecs.linux-foundation.org/cxxabi-1.83.html
主要基类
对于动态类,它与偏移0共享虚拟指针的唯一基类(如果有).它是第一个(以直接基类顺序排列)非虚拟动态基类(如果存在).
动态类
需要虚拟表指针的类(因为它或其基数具有一个或多个虚拟成员函数或虚拟基类).
如何禁止构造物体?我将= delete;所有相关的特殊功能标记如下:
struct A
{
A() = delete;
A(A const &) = delete;
A(A &&) = delete;
void * operator new(std::size_t) = delete;
void operator delete(void *) = delete;
};
A x{};
A y = {};
A * z = ::new A{};
Run Code Online (Sandbox Code Playgroud)
但是x,y和*z仍然可以存在.该怎么办?我对这两种情况都感兴趣; 静态/堆栈分配和堆分配.
这一章在现实世界中OCaml中描述了不同数据类型的运行时内存布局。但是,没有关于惰性值的讨论。
lazy_t实现,即它的运行时表示形式是什么以及编译器内置的主要操作是什么?链接到源代码将不胜感激。我查看了CamlinternalLazy模块,但是仅基于对Obj模块中函数的调用,似乎很难解读实际的表示形式。注意:此问题与 OCaml编译器/运行时有关。据我所知,有如何偷懒值应该由没有实施标准规范的 ocaml的编译器/运行。
我读了一个问题:C ++虚拟类继承对象大小问题,并且想知道为什么虚拟继承会在类中导致附加的vtable指针。
我在这里找到了一篇文章:https : //en.wikipedia.org/wiki/Virtual_inheritance
告诉我们:
但是,通常只能在运行时知道此偏移量,...
我在这里不了解与运行时相关的内容。完整的类继承层次结构在编译时就已经知道。我了解虚函数和基指针的用法,但是虚继承没有这种东西。
有人可以解释为什么某些编译器(Clang / GCC)使用vtable实现虚拟继承以及在运行时如何使用它吗?
顺便说一句,我也看到了这个问题:在虚拟继承的情况下使用vtable,但是它仅指向与虚拟函数相关的答案,这不是我的问题。
memory-layout ×10
c++ ×5
vptr ×2
bit-packing ×1
c ×1
c# ×1
c++11 ×1
c++14 ×1
elf ×1
g++ ×1
heap-memory ×1
inheritance ×1
itanium-abi ×1
linker ×1
ocaml ×1
polymorphism ×1
reflection ×1
swift ×1
type-traits ×1
vtable ×1