最近,在这个问题中,我已经问过如何在C#中获取类的原始内存地址(这是一个粗略的不可靠的黑客和一个不好的做法,除非你真的需要它,否则不要使用它).我成功了,但后来出现了一个问题:根据这篇文章,类原始内存表示中的前2个字应该是指向SyncBlock和RTTI结构的指针,因此第一个字段的地址必须偏移2个字 [ 8个字节 in 从一开始就是32位系统,64 位系统中的16个字节.但是,当我从对象位置的内存中转储第一个字节时,第一个字段与对象地址的原始偏移量只有1个32位字(4个字节),这对两种类型的系统都没有任何意义.从我链接的问题:
class Program
{
// Here is the function.
// I suggest looking at the original question's solution, as it is
// more reliable.
static IntPtr getPointerToObject(Object unmanagedObject)
{
GCHandle gcHandle = GCHandle.Alloc(unmanagedObject, GCHandleType.WeakTrackResurrection);
IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle));
gcHandle.Free();
return thePointer;
}
class TestClass
{
uint a = 0xDEADBEEF;
}
static void Main(string[] args)
{
byte[] cls = new byte[16];
var test = new …Run Code Online (Sandbox Code Playgroud) 如何在 C# 中找到指向托管类的原始指针,并且希望它是内存中的原始大小?显然,这是 CLR 不允许的——更准确地说,是严格禁止的,因为出于稳定性和安全的原因,永远不应该使用托管类的非托管表示形式——所以我正在寻找一个黑客。我不是在寻找序列化 - 我实际上需要一个托管类的转储,因为它在原始内存中表示。
更准确地说,我正在getObjectPtr以下示例中寻找类似函数的东西:
IntPtr getObjectPtr(Object managedClass) {...}
void main() {
var test=new TestClass();
IntPtr* ptr_to_test=getObjectPtr(test);
Console.WriteLine(ptr_to_test.ToString());
}
Run Code Online (Sandbox Code Playgroud)
提前致谢!
编辑: 我终于自己找到了一个解决方案,当我回来将其作为答案发布时,对如此快速发布的答案数量感到非常惊讶......谢谢大家!这非常快,而且完全出乎意料。
最接近我的解决方案是@thehennyy 的解决方案,但我没有发布它,因为@Chino 提出了更好的解决方案(对不起,我一开始误认为它是错误的,我只是忘记再次取消引用指针)。它不需要不安全的代码,并且更能容忍 GC:
class Program
{
// Here is the function in case anyone needs it.
// Note, though, it does not preserve the handle while you work with
// pointer, so it is less reliable than the code in Main():
static IntPtr getPointerToObject(Object unmanagedObject)
{
GCHandle gcHandle = GCHandle.Alloc(unmanagedObject, …Run Code Online (Sandbox Code Playgroud) 当然,Ruby确实有递归,就像任何其他高级编程语言一样.只要递归深度不是太高,这就可以正常工作,但如果是,则会捕获堆栈溢出:
#!/usr/bin/ruby2.0
def rec_naive(i)
return 1 if i==1
rec_naive(i-1) + i
end
puts rec_naive(10000) #(Stack size: ~9360)
#==> test.rb:3: stack level too deep (SystemStackError)
Run Code Online (Sandbox Code Playgroud)
想到的最明显的解决方案是简单地增加堆栈大小.不幸的是,我在这个主题上找到的答案建议以一种或另一种方式改变操作系统状态 - 修改Ruby解释器源代码ulimit,编译标志等 - 这是纯粹的Ruby,当然,并不总是可行,特别是安全的环境.因此,想到的不太明显的解决方案是以非递归方式重写违规函数或重新实现调用堆栈:
# Recursion-free way
def rec_norecurse(i)
acc = 0
(1..i).each do |n|
acc += n
end
return acc
end
puts rec_norecurse(100)
# Reimplementing the call stack
StackFrame = Struct.new(:state, :args)
def rec_customstack(stack)
lastresult = nil
until stack.empty?
frame = stack.last
state, args = frame.state, frame.args
i = args[0] …Run Code Online (Sandbox Code Playgroud)