C 直接访问函数堆栈
我之前问过一些C函数,这些函数接受的参数数量不确定,例如,C 直接访问函数堆栈,c,function,callstack,C,Function,Callstack,我之前问过一些C函数,这些函数接受的参数数量不确定,例如,void foo(){/*code here*/},并且可以使用数量不确定的参数调用 当我问像void foo(){/*code here*/}这样的函数是否可以获取调用它的参数时,例如foo(42,“random”)有人说: 您唯一能做的就是使用调用约定和正在运行的体系结构知识,并直接从堆栈中获取参数 我的问题是: 如果我有这个功能 void foo() { // get the parameters here }; 我称之为
void foo(){/*code here*/}
,并且可以使用数量不确定的参数调用
当我问像void foo(){/*code here*/}
这样的函数是否可以获取调用它的参数时,例如foo(42,“random”)
有人说:
您唯一能做的就是使用调用约定和正在运行的体系结构知识,并直接从堆栈中获取参数
我的问题是:
如果我有这个功能
void foo()
{
// get the parameters here
};
我称之为:foo(“dummy1”、“dummy2”)
是否可以直接从堆栈中获取foo
函数中的两个参数
如果是,如何进行?是否可以访问整个堆栈?例如,如果我递归调用一个函数,是否有可能以某种方式访问每个函数状态
如果没有,那么参数数量未指定的函数有什么意义?这是C编程语言中的错误吗?在哪种情况下,有人希望
foo(“dummy1”、“dummy2”)
为头为void foo()
的函数编译并正常运行?是的,您可以通过堆栈直接访问传递的参数。但是,不能使用旧式函数定义来创建参数数量和类型可变的函数。下面的代码显示了如何通过堆栈指针访问参数。它完全依赖于平台,所以我不知道它是否能在您的机器上工作,但您可以理解
long foo();
int main(void)
{
printf( "%lu",foo(7));
}
long foo(x)
long x;
{
register void* sp asm("rsp");
printf("rsp = %p rsp_ value = %lx\n",sp+8, *((long*)(sp + 8)));
return *((long*)(sp + 8)) + 12;
}
对于这个示例,我在debugger中简单地检查了它,但如果它对您来说真的很重要,我认为您可以为您的机器解决方案提供一些“通用”的工具 如果声明
void foo()
,则会得到foo(“dummy1”、“dummy2”)
的编译错误
您可以声明一个函数,该函数采用以下未指定数量的参数(例如):
如您所见,必须至少指定一个参数。这样,在函数内部,您将能够访问最后一个指定参数之后的所有参数
假设您有以下调用:
short y = 1000;
int sum = func(1,y,5000,"abc");
下面是如何实现func
和访问每个未指定参数的方法:
int func(char x,...)
{
short y = (short)((int*)&x+1)[0]; // y = 1000
int z = (int )((int*)&x+2)[0]; // z = 5000
char* s = (char*)((int*)&x+3)[0]; // s[0...2] = "abc"
return x+y+z+s[0]; // 1+1000+5000+'a' = 6098
}
正如您所看到的,这里的问题是,每个参数的类型和参数的总数都是未知的。因此,任何带有“不适当”参数列表的对func
的调用都可能(也可能会)导致运行时异常
因此,通常,第一个参数是一个字符串(const char*
),它指示以下每个参数的类型以及参数的总数。此外,还有用于提取未指定参数的标准宏-va_start
和va_end
例如,以下是如何实现与printf
行为类似的函数:
void log_printf(const char* data,...)
{
static char str[256] = {0};
va_list args;
va_start(args,data);
vsnprintf(str,sizeof(str),data,args);
va_end(args);
fprintf(global_fp,str);
printf(str);
}
注意:上面的例子不是线程安全的,这里只给出一个例子,。大量的“如果”:
所以这是一个很大的麻烦和假设,基本上什么都不知道。如果你知道它是如何被调用的(参数的类型是什么),你可以用一种依赖于机器的方式来做这件事(但是为什么要有这样一个函数呢?),如果你不知道,你就不知道。还要注意(在现代C语言中)
void foo(){
不接受任何参数<代码>void foo()另一方面,code>(仅声明,不与定义连接)没有说明foo
需要什么。因此,在两个示例中,都不能将任何内容传递给foo。您的示例给出了原型,OP要求给出函数声明的情况。阅读他与gcc4.8.1
链接的问题和答案,我在调用foo(“dummy1”、“dummy2”)时没有收到错误。我知道可变函数,但这不是我的问题。然而,我不知道您用于int func(char x,…)
的方法,我只知道这个例子:@Dabo为什么要删除您的
void log_printf(const char* data,...)
{
static char str[256] = {0};
va_list args;
va_start(args,data);
vsnprintf(str,sizeof(str),data,args);
va_end(args);
fprintf(global_fp,str);
printf(str);
}