6

Suppose source code file name is test.cpp. When it is compiled, it produce test.exe file. When I execute it, it should identify its file name that is test.exe and print it.

I'm able to get list of all the files and directories present in the current directory using following code:

DIR * directory;
struct dirent * direct;
direct = readdir(directory);

But, how can I identify the associated file name, in this case which is "test.exe"?

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
siddstuff
  • 1,215
  • 4
  • 16
  • 37
  • 2
    Why does your C source have a C++ source file extension? The two languages are *not* the same, you realize this? – crashmstr Nov 26 '14 at 12:46
  • 7
    The current directory isn't necessarily where the executable is. On most occasions, it isn't anywhere near it. – molbdnilo Nov 26 '14 at 12:51
  • @Amadeus That is not a duplicate, because it is about a Windows-specific solution. The OP here seems to be looking for a standard solution – Lundin Nov 26 '14 at 12:57
  • 1
    Re-opened, because it wasn't a duplicate. I'm quite certain duplicates exist, but it should be a correct one. – Lundin Nov 26 '14 at 12:58
  • Heh ..you know, I suppose my eyes stopped when I saw "text.exe" and assumed it was for windows/DOS (http://en.wikipedia.org/wiki/.exe) ...but, you're right, he uses readdir() which is indicative of something other than windows. – Amadeus Nov 26 '14 at 13:39
  • 1
    Not possible in general. The program might not have any filename when executing (weird, but possible at least on Linux). – Basile Starynkevitch Feb 19 '15 at 11:52
  • I'm surprise this hasn't been referred to yet: https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe That's close enough that this could have probably been closed as a duplicate. – Andrew Henle Sep 06 '18 at 21:10

5 Answers5

18

In your main function, argv[0] is the name of the executable from the command line

#include <stdio.h>
int main(int argc, char ** argv)
{
    printf("%s", argv[0]);
    return 0;
}

Live Demo

This prints the command name, which is the directory relative to the current working directory, plus the executable name (if available, which is not guaranteed) To get the current working directory, use getcwd() standard library C function.

Extracting the file name from the command path in argv[0] is platform specific : unix use slashes '/', windows allows mixed uses of slash / and backslash \, and any other platform could use any other path separator. Extracting the file name from a path requires a cross-platform library, such as Qt or Boost. On POSIX environments, basename could be used.

Jed Fox
  • 2,979
  • 5
  • 28
  • 38
galinette
  • 8,896
  • 2
  • 36
  • 87
  • 3
    argv[0] is your command, not necessarily the name of the executable – Jonatan Goebel Nov 26 '14 at 12:50
  • @JonatanGoebel : true, in case of symbolic links (do you see other cases where it could be different?) – galinette Nov 26 '14 at 12:56
  • 1
    @galinette See http://stackoverflow.com/questions/2050961/is-argv0-name-of-executable-an-accepted-standard-or-just-a-common-conventi – Peter M Nov 26 '14 at 12:57
  • @galinette, if OP wants only the filename, it is also necessary to call `basename` to remove the path. – Jonatan Goebel Nov 26 '14 at 13:04
  • 1
    `argv[0]` can be absolutely anything. Shells pass the command as entered by the user as `argv[0]`. It may or may not be related to the filename, depending on the shell. In general, programs that run other programs are free to pass anything they want as `argv`. – n. m. could be an AI Nov 26 '14 at 13:33
  • @n.m. You're right in practice, but the standard says that `argv[0]` should be the name used to invoke the program. (Which strictly speaking isn't implementable under Unix. When I invoke one of the `exec` functions, I can set `argv[0]` to whatever I want.) – James Kanze Nov 26 '14 at 14:04
  • **getcwd()** is not standard **C** library its for Linux systems only. – Haseeb Mir Nov 01 '18 at 14:15
13
#include <stdio.h>

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

Note that your program can be launched as:

/home/user/./app

In this case you can get the name by using strrchr:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *appname;

    appname = strrchr(argv[0], '/'); /* '\\' on Windows */
    printf("%s\n", appname ? ++appname : argv[0]);
    return 0;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
7

You know the name of the executable when you're building it; the simplest solution is to embed it in the program, using a -D or /D option to define a macro on the command line.

Other than that, the generic answer is that it isn't possible:

According to the standard

  • argv[0] should contain the name which was used to invoke the program (whatever that means). Which is nice, but 1) it isn't even implementable under Unix, and 2) under most systems, there are all sorts of aliasing which means that the name used to invoke the program bears no relationship to the name of the executable.

Under Windows

  • There's a system function GetModuleFileName which can be used to obtain the path of the executable. Once you've got the path, the last element of the path is the name of your executable.

Under Unix

  • It's fundamentally impossible. When starting a new process, Unix takes separate arguments for the path to the executable and for what ends up in argv[0], so they can potentially have no relationship to one another. It all depends on who starts your process. bash will put the full path to the executable in the environment variable "_", so you can use getenv to get it. But that only works if your program was started by bash. On most Unices, you can also find it in the /proc filesystem, if you know your way around there; but the organization of this varies from one Unix to the next. Note too that because of hard links, you're executable may not have just one name.

The real question is why you want to do this. What is the problem you are trying to solve?

phuclv
  • 37,963
  • 15
  • 156
  • 475
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Do you have a crystal ball? I would never guess that this was what OP need. It was clearly a runtime question for me. – Jonatan Goebel Nov 28 '14 at 19:32
  • @JonatanGoebel The OP asked how to obtain the name of the executable. He may have been thinking run time, but the name is generally known to the build process, and so can be determined at build time. (The OP didn't specify what he was trying to accomplish, so it's hard to say whether this solution would solve the problem or not---I actually have my doubts that it would, since I can't think of a problem that would require this knowledge. But it's what he asked for.) – James Kanze Dec 01 '14 at 17:18
4

On Linux specifically:

you might use proc(5) and the /proc/self/exe symlink, so use readlink(2) on that. Once you did that, you could use basename(3) or realpath(3) on the obtained symlink.

However, be aware that a program might not always have a file path. It could have several file paths (for example /bin/rbash is a symlink to /bin/bash, and the shell process behave differently when invoked as rbash or as bash). Sometimes a given file (actually an inode, see inode(7)) has several hardlinks to it. In weird cases there is none. And it could happen that a program is execve(2)-ed and then removed with unlink(2) (perhaps from another process scheduled to run before yours) etc..

(BTW, your question is OS specific; readdir(3) is POSIX and there are some operating systems not even having directories, and readdir is not mentioned by the C11 standard; check by reading n1570)

I experimented with the following (pathological) ./selfremove program (in my /home/basile/tmp/ directory) which removes its own binary:

 // file selfremove.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>

 int
 main (int argc, char **argv)
 {
   char selfpath[128];
   memset (selfpath, 0, sizeof (selfpath));
   if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0)
     {
       perror ("first readlink");
       exit (EXIT_FAILURE);
     };
   printf ("initial /proc/self/exe -> %s\n", selfpath);
   if (unlink (argv[0]))
     {
       fprintf (stderr, "unlink %s: %m\n", argv[0]);
       exit (EXIT_FAILURE);
     };
   printf ("%s unlinked\n", argv[0]);
   if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0)
     {
       perror ("second readlink");
       exit (EXIT_FAILURE);
     };
   printf ("final /proc/self/exe -> %s\n", selfpath);
   return 0;
 }    

It works, and the kernel is constructing a * (deleted) symlink (since a perverse coder might rename an executable as selfremove (deleted), so that kernel added suffix is only an indication ....):

 % ./selfremove 
 initial /proc/self/exe -> /home/basile/tmp/selfremove
 ./selfremove unlinked
 final /proc/self/exe -> /home/basile/tmp/selfremove (deleted)

So even with /proc/self/exe you cannot always trust the result.

If you assume that your program has been execve(2)-ed by some shell (or similar program doing execvp(3)) -and that is not always the case- then the PATH variable might have been used (and searched from your main's argv[0] if it has no /). You might use getenv(3) as getenv("PATH") to get it from your environment (see environ(7) for more). That $PATH is generally set and used, but they are pathological cases too.

So in general there is no way to reliably print its own executable (as my pathological selfremove.c demonstrates). In most cases you could find it (e.g. by readlink of /proc/self/exe, or by searching in $PATH using argv[0]).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
3

In Linux systems, I think you can also use basename(char *path); from libgen.h, try $ man basename:

Print NAME with any leading directory components removed. If specified, also remove a trailing SUFFIX.

I tried it as:

// filename.c
#include<stdio.h>
#include<stdlib.h>
#include<libgen.h>
int main(int argc, char* argv[]){
    char* exe_name = basename(argv[0]);
    printf(" Executable Name: %s", exe_name);
    printf("\n");
    return EXIT_SUCCESS;
}

Observations,compiled and tested it as:

taxspanner@:~$ ls filename.c
filename.c
taxspanner@:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename
taxspanner@:~$ ls filename*
filename  filename.c
taxspanner@:~$ 

Now run it in current directory:

taxspanner@:~$ ./filename 
 Executable Name: filename

Using absolute path:

taxspanner@:~$ pwd
/home/taxspanner
taxspanner@:~$ /home/taxspanner/filename 
 Executable Name: filename

Relative path:

taxspanner@:~$ cd study/divide-5/
taxspanner@:~/study/divide-5$ pwd
/home/taxspanner/study/divide-5
taxspanner@:~/study/divide-5$ ls ../../filename*
../../filename  ../../filename.c
taxspanner@:~/study/divide-5$ ../../filename
 Executable Name: filename
taxspanner@:~/study/divide-5$ 

one more try with executable name with suffix:

taxspanner@:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename.out
taxspanner@:~$ ./filename.out 
 Executable Name: filename.out
taxspanner@:~$ cd study/divide-5/
taxspanner@:~/study/divide-5$ ../../filename.out 
 Executable Name: filename.out

Be careful when using it: Both dirname() and basename() may modify the contents of path, so it may be desirable to pass a copy when calling one of these functions.

Give it a try!!

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208