1

Hey all, I'm just wondering if it is possible to get the name of the program thats running within a function?

Here's an example:

Say I called: ./runProgram

main() {

A();

}

function A() {

// Possible to retrieve "runProgram" if I cannot use main's argc(argv) constants??
}
Matt
  • 22,224
  • 25
  • 80
  • 116
  • 1
    Can you clarify your question? You state that you "cannot use main's argc(argv) constants" but it is unclear whether: (1) you did not realise that you can easily store or pass as parameters argc/argv from main() to somewhere else; or (2) whether there is some technical restriction preventing you from using argc/argv at all. – Greg Hewgill Oct 19 '09 at 01:09
  • If there's a technical reason, it's a much more interesting question ;-p For example perhaps the function is in a plugin to an existing program, so the signature or main() can't be changed... – Kieron Oct 19 '09 at 01:32
  • oh, haven't noticed he uses the zero param main version oO – Johannes Schaub - litb Oct 19 '09 at 01:43
  • 1
    10 answers for something pretty stupid. We really need better questions around here =/ – toto Oct 19 '09 at 03:11
  • @toto: come on... questions like this are my insanity's playground. – Stefano Borini Oct 19 '09 at 10:16
  • @toto - you're right this was a terribly stupid question haha. though my motives we're clear and evil - beat my CS projects test scripts! Ended up just figuring it out the project on my own though. – Matt Mar 12 '10 at 06:35
  • Possible duplicate of [How can one grab a stack trace in C?](http://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c) – Ciro Santilli OurBigBook.com Mar 19 '17 at 11:54

11 Answers11

5

Compiler dependent, so:

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

Make the program

$ 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

Get the global name of the 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

Add the global name, declared as extern, and keep into account the mangling.

$ 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]);

}

Run the horror

$ 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

Please don't tell my mom.

Stefano Borini
  • 138,652
  • 96
  • 297
  • 431
  • 4
    Despite all these other evils, you could at least `#include ` and get the compiler to shut up. It couldn't hurt. – Chris Lutz Oct 19 '09 at 01:19
  • @Chris: I was in a hurry. And yes, I could have added the header, but it was much better to add a 2>&1 >/dev/null considering the trend of the answer... – Stefano Borini Oct 19 '09 at 03:39
  • Hahaha. First of all I actually Lol'ed at both "Please don't tell my mom" and "You're a wild man". Thanks a lot for your help. – Matt Oct 23 '09 at 05:17
4

This isn't possible in "standard C". If you are into jiggery-pokery, you may be able to look at the environment variables of the program to find the command line. The following works on FreeBSD:

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

#include <stdio.h>

extern char ** environ;

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

int main ()
{
    A ();
}

However, in C itself, unlike languages like JavaScript and Perl, there is no way to take a peek up the stack and find out who called you.

  • I think I was pretty careful to qualify that is "in C itself", not in a particular compiler. –  Oct 19 '09 at 04:37
3

GetCurrentProcessId(); will get you the current Process ID. From there, you will need to match this up with the currently running process name.

See this code project article for more information on step #2.

Chris Ballance
  • 33,810
  • 26
  • 104
  • 151
1

Typically what you would do is use a global variable for this.

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

With trivial variations on this idea, you can save the entire command line array in a global variable if you need to.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

The name of the program will be stored in argv[0].

Note that this is not necessarily the same as the filename that first comes to mind. E.g., if there are symbolic links to the program and the program was invoked using that name, then that is what will be stored in argv[0].

So, for example, you could use the following program:

#include <stdio.h>

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

which would yield the following behavior:

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

Note that shell substitutions occur before the name reaches the program:

$ alias bar=./foo
$ bar
./foo
Andre Stechert
  • 214
  • 1
  • 4
0

Disregarding the fact that your code above is terrible C and is actually closer to pseudocode...

No. You can either assign argv[0] to a global variable so it can be accessed by code elsewhere, or you can pass it as an argument. I doubt there's a standard C way to get into the local variables of another function. It sounds like a rather bad idea anway (in my humble opinion).

Using a global:

char *progname;

void A(void)
{
    // do stuff with progname
}

int main(int argc, char **argv)
{
    progname = *argv;
    A();
    return 0;
}

Passing as an argument:

void A(char *progname)
{
    // do stuff with progname
}

int main(int argc, char **argv)
{
    A(*argv);
    return 0;
}

EDIT: Most of us missed it because it was hidden rather deceptively in the comments, but you say you can't use argv. I just want to note that any solution not using argv is going to be non-portable, and that the best answer is to go ahead and use argv since it's given to you by the standard and there's no conceivable reason you can't use argv. That's like saying "How can I print text to the console without using the stdin filehandle?" You can do it, but why would you want to?

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
0
int main(int argc, char *argv[]) {
  printf("program: %s\n", argv[0]);

  //pass argv[0] to the desired function.
}
jldupont
  • 93,734
  • 56
  • 203
  • 318
0

With Windows you could use the GetCommandLine function. Maybe there's a similar API for Linux.

toto
  • 880
  • 11
  • 21
0

You can probably find the complete command that resulted in your process' execution from a getpid, but the specifics as to how that might be done are going to vary from platform to platform.

Azeem.Butt
  • 5,855
  • 1
  • 26
  • 22
0

Under Linux, you can look at /proc/self/cmdline (or alternatively find the process ID with getpid() and then look at /proc/[pid]/cmdline; the former is a shortcut to the latter.

Kieron
  • 11,588
  • 5
  • 34
  • 29
0

C calling convention on x86 has a stack frame layout like this.

                               ...
                   *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)

Therefore, to get the caller's arguments, start from (%ebp) and walk up. GCC's __builtin_frame_address extension helps with the first step.

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

Unfortunately, main is a bit special, so calling A directly from main will likely crash.

Also, to save work and free up a register, optimizing compilers will may omit this standard stack frame setup, which would also cause this to fail.

ephemient
  • 198,619
  • 38
  • 280
  • 391