How do I get the directory that a program is running from?
Solution 1
Here's code to get the full path to the executing app:
Windows:
char pBuf[256];
size_t len = sizeof(pBuf);
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;
Linux:
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
Solution 2
If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.
getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).
Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.
On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
Solution 3
This is from the cplusplus forum
On windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
On Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
On HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
Solution 4
If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.
If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().
IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)
Solution 5
I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
You can now just use this as a base for your relative path. So for example I have this directory structure:
main
----> test
----> src
----> bin
and I want to compile my source code to bin and write a log to test I can just add this line to my code.
std::string pathToWrite = base + "/../test/test.log";
I have tried this approach on Linux using full path, alias etc. and it works just fine.
NOTE:
If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.
Related videos on Youtube
Markus Joschko
I work with GPUs on deep learning and computer vision.
Updated on February 27, 2022Comments
-
Markus Joschko over 2 years
Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)
(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)
-
David R Tribble over 14 yearsUnless you can reliably extract the path from
argv[0]
, the technique is going to be very OS-dependent. -
colemik about 11 yearsJust to clarify: the 'current directory', or, 'the directory that the program is running from' (in the terminology of the question) is the directory where the image file of the program (~.exe file) is located, and the 'current working directory' is the directory, that is autocompleted if the program uses relative paths?
-
rsethc about 11 yearsWhen you
#include <windows.h>
, Windows automatically puts achar*
to the executable path in_pgmptr
. You don't need to call extra functions or assume junk if you are working on Windows only. -
Gregory Pakosz about 9 yearsDoes that answer your original question? github.com/gpakosz/whereami
-
Hydranix over 8 yearsAlthough the comment is from three years ago, I'd like to expand on rsethc's comment about
_pgmptr
. MSDN documentation states that the_pgmptr
and_wpgmptr
variables are deprecated, and you should use the function_get_pgmptr(char**)
or_get_wpgmptr(wchar_t**)
instead. MSDN -
AirCraft Lover about 5 yearsI tried the Windows' version using Borland C++Builder 6, the pBuf and len parameters are not known. Undefined symbol. What headers should I include?
-
nilo about 4 yearsIf you have a modern compiler, you might want to check stackoverflow.com/a/60804126/3246135.
-
-
Michael Burr almost 16 yearsYou'll need a check to see if an absolute path is given in argv[0]. But more importantly, what if the image is located via the PATH? Does linux fill in the full path or just what's on the command line?
-
Jonathan Leffler almost 16 yearsAs Mike B pointed out, that is a non-general solution; it works in some very limited circumstances only. Basically, only when you run the command by a relative pathname - and it isn't all that elegant when you run ../../../bin/progname instead of ./test
-
Jonathan Leffler almost 16 yearsgetcwd() does not do what the questioner asked.
-
Jonathan Leffler almost 16 yearsFrom the Boost docs: template <class Path> const Path& initial_path(); Returns: current_path() at the time of entry to main(). And current_path() is 'as if by POSIX getcwd()'. This is not what the questioner requested.
-
Michael Burr almost 16 yearsGood answer, but I thought "current working directory" was not what was wanted.
-
Frank Szczerba over 15 yearsI think this is the only answer here that answers the question, and does so for both Windows and Linux. Nice job.
-
SHRISH M about 15 yearsyou should add that even if some documentations say that cCurrentpath can be null and will be allocated by getcwd getcwd does not seem to allocate something on Mac OS and quietly crashes your program
-
andrew cooke over 14 yearswhy has this been marked as the correct answer when the original poster acknowledges that it's not what they wanted?!
-
Joseph White over 14 yearsThere is a small error, but unfortunately I can't edit yet.. line 10: cCurrentpath: should be cCurrentPath
-
asveikau over 14 yearsWhen I see code that looks at
/proc
part of me dies a little. All the world is not Linux, and even on that one platform/proc
should be considered subject to change from version to version, arch to arch, etc. -
asveikau over 14 yearsIMO on Windows the POSIXy-named functions (some of which starting with underscores) should be generally avoided. They aren't the real Windows APIs but rather the CRT. The Windows API you want to use is GetCurrentDirectory(). msdn.microsoft.com/en-us/library/aa364934(VS.85).aspx
-
asveikau over 14 yearsBy the way, a more portable way to get the path to your binary on Unix is to look at
argv[0]
, though this can be forged by the process that launched you. -
Michael Mrozek about 14 years@asveikau
argv[0]
shows the command used to launch the process, so it's only going to show the whole path if the user typed the whole path. If the binary is on their PATH they could just typefoo
to run it, or./foo
if they're in the current directory --argv[0]
would be insufficient either way -
asveikau about 14 years@Michael Mrozek - These are cases that are easily detected. Imagine logic which does: if
argv[0]
begins with'/'
, treat as absolute path, otherwise check if it contains a'/'
, if so it's a relative path and you need to insert the current working directory, otherwise you need to search for your binary in$PATH
. As I said, though, this isn't perfect -- I can callexecve()
withargv[0]
as"omg ponies"
and theexecve()
will still work. -
Andy Dent almost 14 yearsif they launch using an aliased command on Linux is the argv[0] the "name of the command" or expanded?
-
moala about 13 yearssee boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/… for boost 1.46.1
-
Alec Jacobson about 12 yearsI needed to add #include <errno.h> and use char instead of TCHAR to get this to work.
-
allyourcode almost 12 yearsWhy would you divide by sizeof(TCHAR) ? Don't you want to divide by sizeof(char)? Also, isn't the size of char always supposed to be 1? If so, dividing would seem to be superfluous.
-
Jerome almost 12 years@allyourcode TCHAR takes the value char or wchar_t depending on whether you build using Ascii or Unicode. sizeof(wchar_t) is 2 on Windows.
-
colemik about 11 yearsJust to clarify: the 'current directory' is the directory where the image file of the program (~.exe file) is located, and the 'current working directory' is the directory, that is autocompleted if the program uses relative paths?
-
Adrian McCarthy over 10 yearsThe Windows solution isn't checking the return value correctly (or is expecting the caller to do more error checking). Also, it's returning the full path to the executable. If you want just the directory (as the question poses), you then need to strip the file name from the end of the path.
-
Adrian McCarthy over 10 yearsThat Windows solution won't handle non-ANSI characters in the path. You probably should use GetModuleFileNameW and convert it to UTF-8 explicitly (being careful to convert it back whenever you need to issue a filesystem command).
-
HelloGoodbye over 10 yearsFor the Windows solution, I get the error
error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)'
when compiling with MinGW. -
Lucky Luke over 10 yearsMike's answer is correct. The "current directory" is not always as the same as the directory the binary is running from. E.g., if an app runs as a service on Windows, the current directory will probably be C:\Windows\System32, whereas the binary dir is different.
-
Octopus about 10 years@Adrian, Im not generally a windows programmer, but isn't there a DEFINE or someway to tell your compiler to use the _W() flavor of functions automatically?
-
Adrian McCarthy about 10 years@Octopus: To use the wide calls, you'd need to use WCHAR (instead of char) and std::wstring (instead of std::string).
-
Sнаđошƒаӽ about 9 yearsis it not that the accepted answer uses getcwd(), or am I not just understanding?
-
Arnaud about 9 yearsI upvoted because you are the one who came with what is considered the correct answer first.
-
IInspectable about 8 years@LuckyLuke: Or when an application is launched through a shortcut (.lnk), that allows you to specify the current working directory. So querying the CWD before doing anything else in your process won't be helpful either. This answer simply doesn't address the question.
-
jpo38 about 8 yearsAs commented, this gives path from where binary was invoked, not path to the binary...as it could be started from a different folder.
-
jpo38 about 8 yearsIf you resolve possible relative path of argv[0] compared to current directory (because argv[0] could be "../../myprogram.exe"), that's probably the safest way to answer the question. It will always work and is portable (it even works on Android!).
-
charles.cc.hsu almost 8 yearsHow about add
char pBuf[256]; size_t len = sizeof(pBuf);
to let the solution more clearly. -
mrDudePerson over 7 years"Thank you, Mike, you are a hero!" is now proudly present somewhere in the project that I'm currently working on. I also wanted to express my gratitude 'in person', so: thank you, Mike, you are a hero! Yup, it's 3:30 AM.
-
Wodzu over 7 yearsYes, it works on Windows as well. I think that is the best solution. As far as I know argv[0] always keeps path to the executable.
-
S. Saad about 7 yearsFrom the referrenced link,
1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs.
Downvoted, as the OP specifically asks about the current path of the executable rather than the current working directory. -
Xeverous about 7 years
argv[0]
is a very nice idea, but unfortunalety what I'm getting on Linux is "./my_executable_name" or "./make/my_executable_name". Basically what I get depends completely how I launch it -
Salamandar almost 7 yearsYou should use
"/proc/self/exe"
instead of this string copy mojo. Apart from that, great answer ! -
SmallChess over 6 yearsThis answer doesn't even attempt to address the question. Shame on writing it.
-
Beyondo about 6 yearsIt should be
_WIN32
instead ofWINDOWS
,WINDOWS
is more like compiler specific. -
Tim about 6 yearsThis may not be what the person asked for but it is the answer I searched Google for and wanted ^_^ (needed to debug some code and this works perfect for me) Thanks!
-
Cássio Renan about 5 yearsNice answer, but it is undefined behavior to add declarations or definitions to namespace
std
. To avoid this, you can add both the namespacesstd::filesystem
andstd::experimental::filesystem
to a third namespace of your choice, or just useusing std::filesystem::path
, if you don't mind adding the declaration ofpath
to the global namespace. -
TarmoPikaro about 5 yearsI guess after C++14 experimental::filesystem is not used anymore, so you can just forget about this ? (goes into first #if branch)
-
nilo over 4 years@Xeverous: so what? If I have some files relative to my executable that it needs to open, starting from "./" or "./make/" in your cases should work. "." is the current working directory, and argv[0] will tell you the relative path to the executable from there, which is exactly what the OP should want. That is in any case exactly what I need.
-
McLeary about 4 yearsThere is big catch with this function: Multithreaded applications and shared library code should not use the GetCurrentDirectory function and should avoid using relative pathnames. If you can work with this assumption than it is the best solution.
-
dxiv over 3 yearsThis duplicates another previous answer and, unlike that one, will fail in ANSI builds because the unqualified
GetModuleFileName
will resolve toGetModuleFileNameA
instead ofGetModuleFileNameW
. -
The Oathman over 3 yearsI have modified the answer to include both. Much love
-
alle_meije almost 3 yearsvery clean. great answer
-
brc-dd almost 3 yearsSeems to work partially on Windows too (tested on PowerShell Core, Windows PowerShell, MinGW). Running from CMD, this prints a blank string.