tags:

views:

295

answers:

11

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??
}
A: 

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
A: 
int main(int argc, char *argv[]) {
  printf("program: %s\n", argv[0]);

  //pass argv[0] to the desired function.
}
jldupont
I don't think that's what he's asking.
Kinopiko
It's certainly a better way to achieve the goal than what he's asking for.
Chris Lutz
He specifically said that he did not have access to the args
Chris Ballance
@Chris: Intriguing... how can you end-up in a situation like this?
jldupont
+2  A: 

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
+2  A: 

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
Calling GetModuleFileName with NULL as the first parameter would be much more direct
shf301
+1  A: 

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
OP specificaly asked for a way to do this without using argv
Chris Ballance
A: 

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

toto
A: 

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
+3  A: 

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.

Kinopiko
Says you. http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html ;-)
ephemient
I think I was pretty careful to qualify that is "in C itself", not in a particular compiler.
Kinopiko
+5  A: 

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
You're a wild man.
Kinopiko
Despite all these other evils, you could at least `#include <stdio.h>` and get the compiler to shut up. It couldn't hurt.
Chris Lutz
Stefano Borini
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
A: 

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
A: 

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