是否有一个标准repr的调用方法导致Python中的给定堆栈帧?如果不这样做,有没有一种很好的方法可以手动完成?
举个例子:
def some_call(*args, **kwargs):
print('{}({})'.format(
'some_call',
', '.join(itertools.chain(
map(repr, args),
('{}={!r}'.format(k, kwargs[k]) for k in kwargs)))))
>>> some_call(1, 2, a=3)
some_call(1, 2, a=3)
Run Code Online (Sandbox Code Playgroud)
我正在尝试记录某些调用,并且正在编写一个装饰器来记录对包装函数的调用以及完整的详细信息.我错了吗?
我写了一个方法Assert():
[System.Diagnostics.Conditional("DEBUG")]
internal static void Assert(bool condition)
{
if (!condition)
{
var message =
"Line:" + (new System.Diagnostics.StackFrame(1)).GetFileLineNumber() + "\r\n" +
"Column:" + (new System.Diagnostics.StackFrame(1)).GetFileColumnNumber() + "\r\n" +
"Where:" + (new System.Diagnostics.StackFrame(1)).GetMethod().Name;
Log("ASSERTION", message);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么触发时我的行和列都等于0?它应该是调用Debug.Assert(false)的地方.
问候,
这就是我想要实现的:如果有一个方法a()调用 method b(),我想知道谁调用了 method b()。
public void a(){
b();//but it is not necessarily in the same class
}
public void b(){
String method = getCallerMethod();//returns 'a'
}
Run Code Online (Sandbox Code Playgroud)
现在,这可以在 Java 9+ 中使用 API 高效地实现StackWalker。在 Java 8 中,我可以使用Thread.currentThread().getStackTrace()or new Exception().getStackTrace(),但这两种方法都非常慢。我不需要整个堆栈跟踪,我只需要堆栈跟踪中的前一帧,并且只需要该帧中的方法名称(可能还有类名称)。
有没有办法在 Java 8 中有效地实现这一点?
我理解在函数的开头和结尾使用push rbp...pop rbp来保留rbp调用函数的值,因为rbp寄存器是被调用者保留的。然后我理解使用rbp作为当前正在执行的过程的堆栈帧的当前顶部的“约定” 。但与此相关,我有两个问题:
rbp只是一个约定?我可以像r11堆栈帧的基础一样轻松地使用(或任何其他寄存器甚至堆栈上的 8 个字节)吗?rbp寄存器有什么特别之处,或者它只是用作基于历史和约定的堆栈框架?mov %rbp, %rsp在离开函数之前用作“清理”方法?例如,push/pop指令通常是对称的,所以mov %rbp, %rsp只是一种速记方式,有人可以“跳过”执行对称的弹出/添加等操作?什么mov %rbp, %rsp是有用的实际用途?几乎所有时候我在编译器输出中看到它(启用零优化),它似乎是不必要的或多余的,而且我很难想到它实际上可能有用的场景。我试图根据 godbolt.org 上 c++ 中的平方函数来理解这一点。显然,返回、参数和局部变量使用 \xe2\x80\x9crbp -alignment\xe2\x80\x9d 来实现此函数。\n有人可以解释一下这是如何实现的吗?\n在这种情况下 rbp +alignment 会做什么?
\nint square(int num){\n int n = 5;// just to test how locals are treated with frame pointer\n return num * num;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译器(x86-64 gcc 11.1)
\n生成的程序集:
\nsquare(int):\n push rbp\n mov rbp, rsp \n mov DWORD PTR [rbp-20], edi. ;\\\\Both param and local var use rbp-*\n mov DWORD PTR[rbp-4], 5. ;//\n mov eax, DWORD PTR [rbp-20]\n imul eax, eax\n pop rbp\n ret\n\nRun Code Online (Sandbox Code Playgroud)\n void fun2(char *format, ...){
va_list arg_list;
va_start(arg_list, format);
vprintf(format, arg_list);
va_end(arg_list);
}
void fun1(char *format, ...){
fun2(format);
}
int main(){
fun1("test: %d", 100);
}
Run Code Online (Sandbox Code Playgroud)
输出:
测试:100
https://onlinegdb.com/OfdDeSJg_
上面的例子有什么错误或者不推荐的地方吗?
我猜想当调用时,只传递了fun2(format);指向第一个参数()的指针,这是正确的吗?format
当vprintfinfun2访问整数100时,这个整数在哪里?在为 保留的堆栈中fun1,在为 保留的堆栈中fun2,在为 保留的堆栈中vprintf,还是在其他地方?
如果正如我想象的那样,仅将指向第一个参数的指针传递给fun2,这是否意味着当通过fun2访问整数 100 调用的函数和宏时,它们正在访问为 保留的堆栈fun1?
假设有一个用户定义的class Foo。一些帖子表明 C++ 类对象“永远”不会在堆上分配,除非使用new. 但!另一方面,有一些帖子建议从函数中按值返回本地外观的类对象不一定会复制任何数据。所以!这样一个对象的数据首先存储在哪里?还在堆吗?它是否被提升到调用函数的堆栈帧?
class Foo {
...
}
Foo a(int x) {
Foo result;
doabc(x, result);
return result;
}
Foo b(int x) {
Foo result = a(x);
doxyz(x,result);
return result;
}
int main() {
int x;
cin >> x;
Foo result = b(x);
dosomethingelse(result);
cout << result;
}
Run Code Online (Sandbox Code Playgroud)
如果 a 的 Foo 结果不是按值复制的,那么它在哪里分配?堆还是栈?如果在堆上,编译器是否会自动重构代码以插入删除?如果在堆栈上,它会驻留在哪个堆栈帧上?b 的?这是让我想知道的帖子:/sf/answers/1223171211/。谢谢!
关于在x86汇编语言中设置堆栈帧的ebp和esp的使用,我有点混淆.在以下代码中:
section '.code' code readable executable ; define the code section of the file
main: ;main label is where execution begins
push ebp
mov ebp,esp ;set up the base ptr
sub ebp,4 ;subtract 4 from ebp
mov dword [esp],msg
call [printf]
mov dword [esp],p ; pass pause>nul cmd to system to hold the box open
call [system]
mov dword [esp],0 ;pass NULL to exit
call [exit]
Run Code Online (Sandbox Code Playgroud)
程序员从ebp中减去了4,但我不确定原因.通常,我在这里看到ESP减去而不是EBP.在这里从EBP中减去的目的是什么?
我想知道是否有人可以向我解释汇编 ARM 中堆栈指针和帧指针之间的区别
我正在尝试编写一个 100% 迭代的程序,也就是说,函数永远不需要返回,因为在这样的返回之后不会发生任何事情。
换句话说,程序100%处于尾部位置。考虑以下玩具程序:
def foo(): Unit =
bar()
def bar(): Unit =
foo()
try
foo()
catch
case s: StackOverflowError =>
println(" Stack overflow!")
Run Code Online (Sandbox Code Playgroud)
调用 foo 确实会导致堆栈溢出,这并不奇怪,事实上 foo 调用 bar,因为这样 bar 需要堆栈帧,bar 然后调用 foo,后者需要堆栈帧,等等。很明显为什么会发生堆栈溢出错误。
我的问题是,如何按原样定义 foo 和 bar 而不会出现堆栈溢出?像Scheme这样的语言允许这个程序,它们会永远运行,是的,但是堆栈不会增长,因为它知道调用后不需要发生任何事情,例如,来自foo的bar,所以不需要保留foo的堆栈帧呼叫酒吧。显然,scala(即 JVM?)确实使堆栈帧保持活动状态。
现在考虑下一个代码示例:
def foo(): Unit =
foo()
foo()
Run Code Online (Sandbox Code Playgroud)
该程序将永远运行,但永远不会发生堆栈溢出。
我知道 @tailrec 注释,但据我了解,它仅适用于第二个示例之类的情况,但不适用于第一个示例。
有任何想法吗?(我需要第一个示例像第二个示例一样永远运行,而不会出现堆栈溢出。)
recursion callstack scala tail-call-optimization stack-frame