在C中查找函数调用者

时间:2009-10-19 00:51:41

标签: c function

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

以下是一个例子:

说我打电话: ./ runProgram

main() {

A();

}

function A() {

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

11 个答案:

答案 0 :(得分:5)

编译器相关,所以:

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

制作节目

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


int foo() {    
}

$ make x
cc     x.c   -o x
x.c: In function ‘main’:
x.c:2: warning: incompatible implicit declaration of built-in function ‘printf’
$ ./x 
program: ./x

获取argc / v vars的全局名称

$ 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

请不要告诉我的妈妈。

答案 1 :(得分:4)

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

/*    _ _                                               _                   
     (_|_) __ _  __ _  ___ _ __ _   _       _ __   ___ | | _____ _ __ _   _ 
     | | |/ _` |/ _` |/ _ \ '__| | | |_____| '_ \ / _ \| |/ / _ \ '__| | | |
     | | | (_| | (_| |  __/ |  | |_| |_____| |_) | (_) |   <  __/ |  | |_| |
    _/ |_|\__, |\__, |\___|_|   \__, |     | .__/ \___/|_|\_\___|_|   \__, |
   |__/   |___/ |___/           |___/      |_|                        |___/  */

#include <stdio.h>

extern char ** environ;

void A ()
{
    char ** p;
    for (p = environ; *p; p++)
        printf ("%s\n", * p);
}

int main ()
{
    A ();
}

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

答案 2 :(得分:3)

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

有关步骤2的详细信息,请参阅this code project article

答案 3 :(得分:1)

通常你要做的就是使用全局变量。

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;
}

如果您需要这个想法,可以将整个命令行数组保存在全局变量中。

答案 4 :(得分:1)

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

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

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

#include <stdio.h>

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

会产生以下行为:

$ cc t.c
$ ./a.out 
./a.out
$ ln -s a.out foo
$ ./foo
./foo

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

$ alias bar=./foo
$ bar
./foo

答案 5 :(得分:0)

忽略上面的代码是可怕的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文件句柄的情况下将文本打印到控制台?”你可以做到,但你为什么要这样做?

答案 6 :(得分:0)

int main(int argc, char *argv[]) {
  printf("program: %s\n", argv[0]);

  //pass argv[0] to the desired function.
}

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

                               ...
                   *0x4000000c  =  0x60000000  (2nd argument)
                   *0x40000008  =  0x00000001  (1st argument)
                   *0x40000004  =  0x20000000  (return address)
*(old %esp = %ebp = 0x40000000) =  0x3ffffff0  (old %ebp)
                   *0x3ffffffc  =  0x00000000  (1st local)
                   *0x3ffffff8  =  0x00000000  (2nd local)
                               ...
           *(%esp = 0x3ffffff0)                (end of frame)

因此,要获得调用者的参数,请从(%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有点特殊,因此直接从A调用main可能会崩溃。

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