Change the current working directory in C++

94,333

Solution 1

The chdir function works on both POSIX (manpage) and Windows (called _chdir there but an alias chdir exists).

Both implementations return zero on success and -1 on error. As you can see in the manpage, more distinguished errno values are possible in the POSIX variant, but that shouldn't really make a difference for most use cases.

Solution 2

Now, with C++17 is possible to use std::filesystem::current_path:

#include <filesystem>
int main() {
    auto path = std::filesystem::current_path(); //getting path
    std::filesystem::current_path(path); //setting path
}

Solution 3

For C++, boost::filesystem::current_path (setter and getter prototypes).

A file system library based on Boost.Filesystem will be added to the standard.

Solution 4

This cross-platform sample code for changing the working directory using POSIX chdir and MS _chdir as recommend in this answer. Likewise for determining the current working directory, the analogous getcwd and _getcwd are used.

These platform differences are hidden behind the macros cd and cwd.

As per the documentation, chdir's signature is int chdir(const char *path) where path is absolute or relative. chdir will return 0 on success. getcwd is slightly more complicated because it needs (in one variant) a buffer to store the fetched path in as seen in char *getcwd(char *buf, size_t size). It returns NULL on failure and a pointer to the same passed buffer on success. The code sample makes use of this returned char pointer directly.

The sample is based on @MarcD's but corrects a memory leak. Additionally, I strove for concision, no dependencies, and only basic failure/error checking as well as ensuring it works on multiple (common) platforms.

I tested it on OSX 10.11.6, Centos7, and Win10. For OSX & Centos, I used g++ changedir.cpp -o changedir to build and ran as ./changedir <path>.

On Win10, I built with cl.exe changedir.cpp /EHsc /nologo.

MVP solution

$ cat changedir.cpp

#ifdef _WIN32
#include <direct.h>
// MSDN recommends against using getcwd & chdir names
#define cwd _getcwd
#define cd _chdir
#else
#include "unistd.h"
#define cwd getcwd
#define cd chdir
#endif

#include <iostream>

char buf[4096]; // never know how much is needed

int main(int argc , char** argv) {

  if (argc > 1) {
    std::cout  << "CWD: " << cwd(buf, sizeof buf) << std::endl;

    // Change working directory and test for success
    if (0 == cd(argv[1])) {
      std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl;
    }
  } else {
    std::cout << "No directory provided" << std::endl;
  }

  return 0;
}

OSX Listing:

$ g++ changedir.c -o changedir
$ ./changedir testing
CWD: /Users/Phil
CWD changed to: /Users/Phil/testing

Centos Listing:

$ g++ changedir.c -o changedir
$ ./changedir
No directory provided
$ ./changedir does_not_exist
CWD: /home/phil
$ ./changedir Music
CWD: /home/phil
CWD changed to: /home/phil/Music
$ ./changedir /
CWD: /home/phil
CWD changed to: /

Win10 Listing

cl.exe changedir.cpp /EHsc /nologo
changedir.cpp

c:\Users\Phil> changedir.exe test
CWD: c:\Users\Phil
CWD changed to: c:\Users\Phil\test

Note: OSX uses clang and Centos gnu gcc behind g++.

Solution 5

Does chdir() do what you want? It works under both POSIX and Windows.

Share:
94,333
sparkFinder
Author by

sparkFinder

Updated on July 09, 2022

Comments

  • sparkFinder
    sparkFinder almost 2 years

    How can I change my current working directory in C++ in a platform-agnostic way?

    I found the direct.h header file, which is Windows compatible, and the unistd.h, which is UNIX/POSIX compatible.

    • Jonathan Mee
      Jonathan Mee over 7 years
      @noɥʇʎPʎzɐɹC So the standard committee has established a standard required way to change the working directory, circa C++17, via filesystem. pepper_chico's answer already denotes that. filesystem is currently available in g++5.3 and Visual Studio 2015 as an optional include. If that is the environment that you're working in I can write you an answer using #ifdef to make filesystem's access cross platform?
    • noɥʇʎԀʎzɐɹƆ
      noɥʇʎԀʎzɐɹƆ over 7 years
      @JonathanMee if it is good enough, I may do a multiple bounty
  • sparkFinder
    sparkFinder almost 14 years
    I'm asking since Visual Studio wants me to use direct.h, but when I try building the same code in Linux, it crashes on my head, saying that I need to use unistd.h
  • rubber boots
    rubber boots almost 14 years
    In boost::filesystem, there wasn't a "chdir" when I used it last time.
  • RBerteig
    RBerteig almost 14 years
    @sparkFinder, you will usually need to include different headers on different platforms when dealing with nonstandard functions such as chdir(). IIRC, GCC will define _WIN32 when targeting Windows, so you could use that with #include to choose a header.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 14 years
    @rubber: indeed, looking at boost.org/doc/libs/1_34_1/boost/filesystem/operations.hpp suggests that there is a getcwd equivalent but no chdir equivalent.
  • AndiDog
    AndiDog almost 14 years
    @sparkFinder: You can check for Visual Studio with #ifdef _MSC_VER and then include the direct.h header. If it's not defined, use unistd.h. This should be enough as the other major programming environment on Windows, MinGW, has the unistd header.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE almost 14 years
    You could just declare the prototype yourself.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    chdir on windows is deprecated.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    Good example. But clean up and shorten your code and it will be yours.
  • MarcD
    MarcD over 7 years
    @ noɥʇʎPʎzɐɹC How's that? I shortened it a bit and cleaned it up. Can't shorten it much more.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    Cleaned it up a bit. I'll test it and put an example run for posix and then you'll get the bounty. :)
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    did a mini code review: gist.github.com/CrazyPython/152805717b1c01649f0efed3415001e0 (it doesn't work on unix)
  • MarcD
    MarcD over 7 years
    It works as expected. What do you want it to do? but doesn't escape it gets converted to a string
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
  • dbush
    dbush over 7 years
    @noɥʇʎPʎzɐɹC Nothing about it being deprecated on this page. What's your source?
  • Jonathan Mee
    Jonathan Mee over 7 years
    @dbush _chdir != chdir _chdir is not cross platform while chdir is deprecated.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    give a clean and isolated one-liner for changing and viewing the current working directory.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    and a function for those who want it, please
  • Nikita
    Nikita over 7 years
    @noɥʇʎPʎzɐɹC Added several helper functions to work both with std::string and boost::filesystem::path.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    would you mind using lowercase_with_underscores, as this is the typical C++ convention?
  • Nikita
    Nikita over 7 years
    @noɥʇʎPʎzɐɹC Not a problem, names updated to comply with boost naming and typical C++ code-style.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    I proposed an edit that shortens the names by a lot and changes get_cwd to a function that returns a string, most people will want the string.
  • Nikita
    Nikita over 7 years
    @noɥʇʎPʎzɐɹC Thnx, changes accepted. I also shorten a variable names there.
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    ooh, you put a lot of effort into this. You're leading on my list!
  • noɥʇʎԀʎzɐɹƆ
    noɥʇʎԀʎzɐɹƆ over 7 years
    Shorter than with libraries, and clean and neat. Provide a clear explanation of how to set and get the cwd, it's a bit vague right now.
  • siphr
    siphr over 7 years
    This answer is not correct as it promotes the use of a deprecated functionality as stated here msdn.microsoft.com/en-us/library/ms235420.aspx
  • Phil
    Phil over 7 years
    @noɥʇʎPʎzɐɹC let me know if the update isn't clear to you.
  • Michael
    Michael over 6 years
    I could see how one might think C and C++ were completely different languages if they were the only two languages you knew. or if C is the only language you knew
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 6 years
    @Michael C and C++ have many characteristics in common: they're unsafe, imperative languages. They nonetheless are completely different languages, further apart than, say, C# and Java. It's true that C and C++ have a rather large common subset, but that common subset is almost never good C or good C++. If you think that C is a subset of C++, you're either a bad C programmer, or a bad C++ programmer, or both.
  • Dietrich Baumgarten
    Dietrich Baumgarten about 4 years
    Doesn't work for me on Windows. What is the purpose of the condition argc > 1? Apps without parameters are allowed to have a working directory.
  • Phil
    Phil almost 4 years
    @DietrichBaumgarten - are you seeing an error? The argc condition is to protect the indexing into argv in the demonstration program.
  • Dietrich Baumgarten
    Dietrich Baumgarten almost 4 years
    No Phil, everything ok, my mistake. I thought your solution required that the program has arguments, but you only used them for demonstration.
  • Marche Remi
    Marche Remi over 2 years
    This changes only the current process's path. The operating shell's current path is not changed.
  • HiddenWindshield
    HiddenWindshield over 2 years
    @MarcheRemi Yes, that's typically what's meant when you want to change the current working directory. Under most OSs, it's not possible to change any other process' working directory at all.