在C中查找函数调用者

嘿所有,我只是想知道是否有可能获得在函数内运行的程序的名称?

这是一个例子:

我打电话说: ./ runProgram

main() { A(); } function A() { // Possible to retrieve "runProgram" if I cannot use main's argc(argv) constants?? } 

编译器依赖,所以:

 $ cc --version i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) 

制作节目

 $ more xc int main(int argc, char *argv[]) { printf("program: %s\n", argv[0]); foo(); } int foo() { } $ make x cc xc -ox xc: In function 'main': xc:2: warning: incompatible implicit declaration of built-in function 'printf' $ ./x program: ./x 

获取argc / v变量的全局名称

 $ nm ./x 0000000100000efe s stub helpers 0000000100001048 D _NXArgc 0000000100001050 D _NXArgv 0000000100001060 D ___progname 0000000100000000 A __mh_execute_header 0000000100001058 D _environ U _exit 0000000100000eeb T _foo 0000000100000eb8 T _main U _printf 0000000100001020 s _pvars U dyld_stub_binder 0000000100000e7c T start 

添加全局名称,声明为extern,并考虑到重整。

 $ more x2.c int main(int argc, char *argv[]) { printf("program: %s\n", argv[0]); foo(); } int foo() { extern char **NXArgv; printf("in foo: %s\n", NXArgv[0]); } 

跑恐怖

 $ make x2 cc x2.c -o x2 x2.c: In function 'main': x2.c:2: warning: incompatible implicit declaration of built-in function 'printf' x2.c: In function 'foo': x2.c:9: warning: incompatible implicit declaration of built-in function 'printf' $ ./x2 program: ./x2 in foo: ./x2 

请不要告诉我的妈妈。

GetCurrentProcessId(); 将为您提供当前的进程ID。 从那里,您需要将其与当前运行的进程名称进行匹配。

有关步骤2的更多信息,请参阅此代码项目文章 。

这在“标准C”中是不可能的。 如果你是jiggery-pokery,你可以查看程序的环境变量来查找命令行。 以下适用于FreeBSD:

 /* _ _ _ (_|_) __ _ __ _ ___ _ __ _ _ _ __ ___ | | _____ _ __ _ _ | | |/ _` |/ _` |/ _ \ '__| | | |_____| '_ \ / _ \| |/ / _ \ '__| | | | | | | (_| | (_| | __/ | | |_| |_____| |_) | (_) | < __/ | | |_| | _/ |_|\__, |\__, |\___|_| \__, | | .__/ \___/|_|\_\___|_| \__, | |__/ |___/ |___/ |___/ |_| |___/ */ #include  extern char ** environ; void A () { char ** p; for (p = environ; *p; p++) printf ("%s\n", * p); } int main () { A (); } 

但是,在C本身中,与JavaScript和Perl等语言不同,没有办法偷看堆栈并找出谁给你打电话。

通常,您要做的是使用全局变量。

 const char *g_argv0; void A() { printf("program is %s\n", g_argv0); } int main(int argc, char *argv[]) { g_argv0 = argv[0]; A(); return 0; } 

对于这个想法的微不足道的变化,如果需要,可以将整个命令行数组保存在全局变量中。

程序名称将存储在argv [0]中。

请注意,这不一定与首先想到的文件名相同。 例如,如果有程序的符号链接,并且使用该名称调用程序,那么这将存储在argv [0]中。

因此,例如,您可以使用以下程序:

 #include  int main(int argc, char **argv) { printf("%s\n", argv[0]); return 0; } 

这会产生以下行为:

 $ cc tc $ ./a.out ./a.out $ ln -s a.out foo $ ./foo ./foo 

请注意,在名称到达程序之前发生shell替换:

 $ alias bar=./foo $ bar ./foo 
 int main(int argc, char *argv[]) { printf("program: %s\n", argv[0]); //pass argv[0] to the desired function. } 

使用Windows,您可以使用GetCommandLine函数。 也许Linux有一个类似的API。

您可以找到导致您的进程从getpid执行的完整命令,但有关如何执行此操作的具体信息因平台而异。

无视上面的代码是可怕的C并且实际上更接近伪代码的事实……

不可以。您可以将argv[0]分配给全局变量,以便可以通过其他地方的代码访问它,也可以将其作为参数传递。 我怀疑是否有一种标准的C方式来进入另一个函数的局部变量。 这听起来像是一个相当糟糕的主意(以我的拙见)。

使用全局:

 char *progname; void A(void) { // do stuff with progname } int main(int argc, char **argv) { progname = *argv; A(); return 0; } 

作为论点传递:

 void A(char *progname) { // do stuff with progname } int main(int argc, char **argv) { A(*argv); return 0; } 

编辑:我们大多数人错过了它,因为它在评论中隐藏着相当具体,但你说你不能使用argv 。 我只想指出,任何不使用argv解决方案都是不可移植的,最好的答案是继续使用argv因为它是由标准给你的,并且没有任何可能的原因你不能使用argv 。 这就像说“如何在不使用stdin文件句柄的情况下将文本打印到控制台?” 你可以做到,但你为什么要这样做?

在Linux下,您可以查看/proc/self/cmdline (或者使用getpid()查找进程ID,然后查看/proc/[pid]/cmdline ;前者是后者的快捷方式。

x86上的C调用约定具有这样的堆栈帧布局。

                                ...
                    * 0x4000000c = 0x60000000(第二个参数)
                    * 0x40000008 = 0x00000001(第一个参数)
                    * 0x40000004 = 0x20000000(返回地址)
 *(旧%esp =%ebp = 0x40000000)= 0x3ffffff0(旧%ebp)
                    * 0x3ffffffc = 0x00000000(第一局)
                    * 0x3ffffff8 = 0x00000000(第二局部)
                                ...
            *(%esp = 0x3ffffff0)(帧结束)

因此,要获得调用者的参数,请从(%ebp)并向上走。 GCC的__builtin_frame_address扩展有助于第一步。

 A() { void **ebp = __builtin_frame_address(1); void **ra = ebp + 1; int *argc = ra + 1; char ***argv = argc + 1; int i; for (i = 0; i < *argc; i++) printf("[%d] %s\n", i, (*argv)[i]); } a(int argc, char **argv) { A(); } main(int argc, char **argv) { a(argc, argv); } 

不幸的是, main有点特殊,所以直接从main调用A可能会崩溃。

此外,为了节省工作并释放寄存器,优化编译器可能会省略此标准堆栈帧设置,这也会导致失败。