在GCC C中,有没有办法将数据推送/弹出到C返回堆栈?
我不是在谈论实现我自己的堆栈(我知道如何做到这一点);我的意思是使用现有的C返回堆栈来显式地推送/弹出参数(当然,在同一级别的大括号内)。
例如:
extern int bar;
void foo(void) {
PUSH(bar);
bar = 12;
doSomething(); // that depends on the value of bar
bar = POP(); // restore original value of bar
}
如果有任何简单的方法可以做到这一点,我认为使用像#34; oldBar"这样的局部变量将是一个更干净的选择。明确。
答案 0 :(得分:8)
如果使用临时变量,它基本上是相同的。临时变量在堆栈上分配或优化到寄存器。
e.g。
extern int bar;
void foo(void) {
int tmp = bar
bar = 12;
doSomething(); // that depends on the value of bar
bar = tmp; // restore original value of bar
}
显然,C实际上并不需要将堆栈结构用于调用,因此这种功能没有意义。这是在本文的内存布局部分https://www.seebs.net/c/c_tcn4e.html
中声明的很简单,并非每个编译器都有“堆栈”。有些系统实际上没有任何此类功能。 C的每个编译器都有某种处理函数调用的机制,但这并不意味着它是一个堆栈。更重要的是,功能参数或局部变量通常不存储在任何“堆栈”中,而是存储在CPU寄存器中。这种区别可能很重要,而且应该被覆盖,而不是手工挥手。
从技术上讲,您也可以使用alloca()(位于alloca.h中)来执行此操作,但释放该内存的唯一方法是返回函数调用。它也没有真正做你所建议的。 alloca不是C标准的一部分
答案 1 :(得分:0)
如果您使用纯C编写,则可以使用可变参数函数。当然,这不是一个完整的解决方案,因为只有在调用函数时才会在函数调用和参数被推送后清除堆栈。 但如果您需要按照您的描述使用它,它可能会起作用:
extern int bar;
void doSomething(...);
void foo(void) {
doSomething(&bar);
//you do not need here to pop to restore the bar value, as you push a copy of value
}
如果你想在推送后做一些其他动作(我甚至无法想象),你可以使用包装函数。
extern int bar;
void doSomething();
void doSomethingWrapper(...) {
//here arguments that are passed in ... are pushed
doSomething();
//and here they are poped
}
void foo(void) {
//....
doSomethingWrapper(&bar);
//....
}
如果您只想以巧妙的方式操作堆栈,唯一的解决方案是使用内联汇编。或者您可以调用函数void push(...)
来推送您想要的任何内容,并在longjmp()
的主体中使用push()
,以避免在控制流离开函数时弹出参数。
答案 2 :(得分:0)
好的,这就是我想要的:
#define PUSHINT(var) int old__##var = var
#define POPINT(var) var = old__##var
extern int bar;
void foo(void) {
PUSHINT(bar);
bar = 12;
doSomething(); // that depends on the value of bar
POPINT(bar); // restore original value of bar
}
如果我能保证“old__”前缀每次都是唯一的,那会更好,但我不知道该怎么做(这不太可能是一个问题)。
它也没有真正做到PUSH / POP(尽管它确实存储在返回堆栈上,至少在我的硬件上)。您不能推送一个值并弹出另一个值。
但我首先不想这样做。
我可以将宏重命名为SAVE()和RESTORE()...
(感谢@ BobbySacamano的回答提示。)