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"?

7
  • 2
    Why does your C source have a C++ source file extension? The two languages are not the same, you realize this? Commented Nov 26, 2014 at 12:46
  • 7
    The current directory isn't necessarily where the executable is. On most occasions, it isn't anywhere near it. Commented Nov 26, 2014 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 Commented Nov 26, 2014 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. Commented Nov 26, 2014 at 12:58
  • 1
    Not possible in general. The program might not have any filename when executing (weird, but possible at least on Linux). Commented Feb 19, 2015 at 11:52

5 Answers 5

19

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.

Sign up to request clarification or add additional context in comments.

7 Comments

argv[0] is your command, not necessarily the name of the executable
@JonatanGoebel : true, in case of symbolic links (do you see other cases where it could be different?)
@galinette, if OP wants only the filename, it is also necessary to call basename to remove the path.
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.
|
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;
}

7 Comments

have you heard about basename?
basename is posix, not stdlib, isn't it?
@galinette, yes, is part of POSIX
Won't work under Windows, which has backslashes. Actually, since paths is a platform specific question, it cannot be answered simply without a platform abstraction library such as Qt (Boost?)
@Alter Mann : he has .exe extension, which other platform than Windows use it ??
|
8

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?

2 Comments

Do you have a crystal ball? I would never guess that this was what OP need. It was clearly a runtime question for me.
@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.)
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]).

Comments

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!!

2 Comments

Nice explanation! And I didn't know that a program in a relative path can be launched using program*
@AlterMann Sorry it was typo in my answer, for relative path we don't need *, I just used ../../filename

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.